有一个整数n,写一个函数f(n),返回0到n之间出现的"1"的个数。

来源:互联网 发布:网络测速在线测网速 编辑:程序博客网 时间:2024/04/29 16:13

问题:有一个整数n,写一个函数f(n),返回0到n之间出现的"1"的个数。

算法问题,我的理解考察用程序解决问题的能力,充分体现一个人从代码层面的生产力,这也是程序员赖以生存的基本技能。

解决问题有思路,但是思路有好坏之分。思维深度和效率是一个矛盾。思维难度越小的算法通常执行效率越差,需要综合平衡。

通常程序实现应非常追求效率。


算法一:从0到n,对其中的每个整数x分别做判断,判断x中含有几个整数1,并返回,外层循环将所有的结果加和即可。

public int countOneNumber(int data) {    int totalCount = 0;    for (int i= 0; i<= data; i++) {        totalCount += oneCount(i);    }    return totalCount;}private int oneCount (int x) {    int count = 0;    while(x >0) {        int left = x % 10;        if(left == 1) {            count ++;        }        x = x/10;    }    return count;}

这样,这一问题就解决了。算法的复杂度O(n*log10n)

想想有没有更高效的算法。

分析一下,比如446这个数的答案的组成

(1)百位为1

  (2)十位为1

(3)各位为1

百位为1,其中包含的数1XX, X每一位可取值0-9, 共10 × 10 = 100 个

十位为1,其中包含的数X1Y,X可取值1,2,3,4,外加一个0, 010 ---> 就是10, 共 5 × 10 = 50个

各位为1,其中包含的数XX1, 前面可取值从 001 ---> 441, 共 55个。

结果:205


有了以上的分析,总结规律。注意条件限制,如果当前位置本来为0,那么这个就不用往上加。

当前位置为1所能组成的数字各位算法为,abc1def = (abc + 1) * 1000, 这个数字左边的所有位组成的数字 + 1, 如果右边有三位数字,则乘以10的三次方。

好了,放程序


public int countOneNumber(int data) {    int totalCount = 0;    int i = 10;    int all = data;    while(true) {        if(all <= 0) {            break;        }        int left = all % 10;        all = all /10;        if (left < 1) {            totalCount += 0;        } else {            totalCount += (data / i + 1) * (i / 10);        }        i = i * 10;    }    return totalCount;}
 

算法时间复杂度 O(log10  n)



  




0 0
原创粉丝点击