`
pandonix
  • 浏览: 400022 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

计算1到N中包含数字1的个数

阅读更多

今天看到一道有趣的算法题,题目如下:

N为正整数,计算从1到N的所有整数中包含数字1的个数。比如,N=10,从1,2...10,包含有2个数字1。

 

相信很多人都能立刻得出以下的解法:

  for(n:N)

  {

          判断n包含1的个数;

          累加计数器;

  }

这是最直接的解法,但遗憾的是,时间复杂程度为O(N*logN)。因为还需要循环判断当前的n的各位数,该判断的时间复杂程度为O(logN)。

接下来就应该思考效率更高的解法了。说实话,这道题让我想起另外一道简单的算法题:

N为正整数,计算从1到N的整数和。

很多人都采用了循环求解。然后利用初等数学知识就知道S=N*(N+1)/2,所以用O(1)的时间就可以处理。

再回到本道题目,同理应该去寻找到结果R与N之间的映射关系。

分析如下:

假设N表示为a[n]a[n-1]...a[1],其中a[i](1<=i<=n)表示N的各位数上的数字。

c[i]表示从整数1到整数a[i]...a[1]中包含数字1的个数。

x[i]表示从整数1到10^i - 1中包含数字1的个数,例如,x[1]表示从1到9的个数,结果为1;x[2]表示从1到99的个数,结果为20;

当a[1]=0时,c[1] = 0;

当a[1]=1时,c[1] = 1;

当a[1]>1时,c[1] = 1;

 

当a[2]=1时,c[2] = a[1] +1+ c[1] + x[1];

当a[2]>1时,c[2] = a[2]*x[1]+c[1]+10;

 

当a[3]=1时,c[3] = a[2]*a[1] +1+ c[2] + x[2];

当a[3]>1时,c[3] = a[3]*x[2]+c[2]+10^2;

......

 

以此类推

当a[i]=1时,c[i] = a[i-1]*...*a[1] +1+ c[i-1]+x[i-1];

当a[i]>1时,c[i] = a[i]x[i-1]+c[i-1]+10^(i-1);

 

 

实现的代码如下:

    public static int search(int _n)   
    {   
        int N = _n/10;   
        int a1 = _n%10,a2;   
        int x = 1;
        int ten = 10;
        int c = a1 == 0?0:1;
        while(N > 0)   
        {   
            a2 = N%10;
            if(a2 == 0);
            else if(a2 == 1)c = a1 + 1 + x + c;   
            else c = a2*x + c + ten;   
            a1 = 10*a1 + a2;     
            N /=10;   
            x = 10*x + ten;
            ten *= 10; 
        }   
        return c;   
    }

 

 

而以上解法的时间复杂程度只有O(logN)

 

如果您路过这里,您有更好的解法吗?:)

3
0
分享到:
评论
6 楼 waiting90 2009-01-11  
lggege 写道

StringBuffer.append() 将它们拼成一个String, 再从头到尾数

这样很慢,很慢...
5 楼 pandonix 2008-06-19  
非常感谢ywergs,以前的算法确实存在问题。惭愧啊,分析不仔细。
问题原因:
代码中没有考虑到a1=0的情况,因为如果a1=0,则c1=0。造成当a2=1,a1=0时,按照c2=a1+1+x1+c1来计算,而c1被初始化为1,所以c2=0+1+1+1=3。
问题解决:
初始化c1时,需要根据a1来初始化,其中c1=a1==0?0:1
这样一来就可以测试:
N(20) = 2*1+10 = 12;N(19) = 9 + 1 + 1 + 1 = 12;所以N(20) = N(19)
N(10) = 0 + 1 + 1 = 2;

再次感谢ywergs,欢迎继续讨论和拍砖
4 楼 ywergs 2008-06-19  
恕我愚笨,我怎么觉得LZ的这个有点问题呢?
比如,当我们用20来测试时,他应该走入else语句!
那么 c20 = 2 * 1 + 1 + 10 = 13
但从直观角度来看数字20 和 19 他们区间包含一个数应该是一样的,可是,如果算19的话,应该走的是if的,这时候, c19 = 9 + 1 + 1 + 1 = 12
从而有:
    c20 != c19
当然,我也为LZ的精湛思路所折服!
不过我也没有想到一个比较好的方法!
写到这里,发觉根本不用20来做测试,就是用10来做测试就有问题了!
按照LZ的思路,10的时候,算出来 应该是 3 ,可是,1-10之间只有2个1的!
3 楼 jasongreen 2008-06-18  
google面试题阿
2 楼 pandonix 2008-06-18  
楼上的解法不错,但时间复杂程度也是O(N+logN)以上,同时也忽略了API,Integer.parseInt的处理时间。
1 楼 lggege 2008-06-18  
StringBuffer.append()

将它们拼成一个String, 再从头到尾数

相关推荐

    (android demo)算法实现:计算十进制数N的二进制形式中包含数字1的个数

    (android demo)算法实现:计算十进制数N的二进制形式中包含数字1的个数

    C++计算一个数字的二进制中0或1的个数原理及代码

    C++计算一个数字的二进制中0或1的个数原理及代码

    C++求1到n中1出现的次数以及数的二进制表示中1的个数

    例如输入 12,从 1 到 12 这些整数中包含 1 的数字有 1, 10, 1 1 和 12, 1 一共出现了 5 次 代码实现(GCC编译通过): #include stdio.h #include stdlib.h int count1(int n); int count2(int n); int main...

    统计1到n之间所有含1的数字个数,并找出n以内最大的那个f(m)=m的值

    统计1到n之间所有含1的数字个数f(n),并找出n以内最大的那个f(m)=m的值,f(n)的时间复杂度为O(logn),找最大的那个f(m)=m的值的时间复杂度为O(n)。... 判断n包含1的个数; 累加计数器; } 完全一致

    剑指Offer(Python多种思路实现):1~n整数中1出现的次数

    例如,输入12,1~12这些整数中包含1的数字有1,10,11,12一共出现了5次。 解题思路一:直接累加1~n中每个整数中1出现的次数。 class Solution: def NumberOf1Between1AndN_Solution(self, n): # write code here...

    汇编语言 20个练习题目 代码加实验报告

    5.6 编写程序,将一个包含有20个数据的数组M分成两个数组:正数数组P和负数数组N,并分别把这两个数组中的数据的个数显示出来。 5.7 试编制一个汇编语言程序,求出首地址为DATA的100D字数组中的最小偶数,并把它放在...

    西南交大-算法设计与分析-作业7-参考(代码+报告)

    (1)对于给定的正整数集合S={w_1,w2,……,wn}和正...(3)给定一个自然数N,0\leN\le4999和M各不同的十进制数字X1,X2,……,XM, 找出由这些数字所构成的正整数中N的倍数最小的正整数,设该正整数不超过232-1。 (4)

    浙江大学C语言上机练习题附答案

    20015当n为152时,分别求出n的个位数字(digit1)、十位数字(digit2)和百位数字(digit3)的值。 3 20026 输入2个整数 num1 和 num2,计算并输出它们的和、差、积、商与余数。 4 第3周(M3) 5 20031 求1+2+3+......+100...

    1~n整数中1出现的次数的奇妙技巧之“完爆官方,包学包会包拓展,告别死记硬背”

    输入一个整数 n ,求1~n这n个整数的十进制表示中1出现的次数。 例如,输入12,1~12这些整数中包含1 的数字有1、10、11和12,1一共出现了5次。 来源:力扣(LeetCode) 奇妙解答 以大家熟知的数字“1024”为例,...

    C语言编程训练:循环结构-求阶乘末尾零个数

    输入的第一行是一个单个的确定的正整数T,他指名接下来的数字的个数,然后是 T 行,每一行包括一个确定的正整数N,1&lt;=N&lt;=1,000,000,000。 【输出说明】 对每一个数字N,产生一行输出包括一个非负整数Z(N)。 【样例...

    湖南省计算机考试C语言机考试题(20220102112033).pdf

    3. 已知f(0)=f(1)=1,f(2)=0,f(n)=f(n-1)-2*f(n-2)+f(n-3)(n&gt;2),求f(0)到f(50)中的最大值。 考试题十 1. 已知:S=2+4+8+16+32+,,求S不大于1500的最大值。 2. 已知数列:f(0)=1,f(1)=2...

    C语言练习之11道算法题 源码

    1.分别求字符串中包含字母、空格、数字和其它字符的个数 2.求表达式结果 3.求素数 4.求天数 5.求一个正整数的各位数字之和 6.求最大公约数&最小公倍数 7.杨辉三角 8.兔子数列(斐波那契数列) 9.组成无重复数字的三位...

    上海电机学院C语言实训答案

    说明:输入的第1个数表示学生人数(n=9),接着输入的9个成绩中,累加和为628.5(所有小数均保留一位小数输出),平均分为69.8分;平均分以上(A档)有4人,占44.4%,平均分以下(B档)有5人,占55.6%;A档的最低...

    2021 CSP-J1 junior-C++ 初赛 第1轮 真题 .pdf

    13. 考虑如下递归算法 solve(n) if n&lt;=1 return 1 else if n&gt;=5 return n*solve(n-2) else return n*solve(n-1) 则调用 solve(7)得到的返回结果为( )。 答案:C. 210。递归算法 solve(n) 的返回结果为 210。 14....

    C语言编程训练-循环结构-求阶乘

    输入的第一行是一个单个的确定的正整数T,他指名接下来的数字的个数,然后是T行,每一行包括一个确定的正整数N,1&lt;=N&lt;=1,000,000,000。 【输出说明】 对每一个数字N,产生一行输出N!计算结果,用科学记数法输出。 ...

    C语言竞赛题

    包含近年所有C语言竞赛题目。

    2019 CSP-S组 第1轮 初赛 答案+解析 好--13页.pdf

    答案是D,解析是n个点最多n(n+1)/2条边,要不连通,至少去掉n-1条边n(n+1)/2-(n-1)≥28,n最小为8。 试题9:一些数字可以颠倒过来看,例如0、1、8颠倒过来看还是本身,6颠倒过来是9,9颠倒过来看还是6,其他数字...

    javascript入门笔记

    1、从弹框中,分两次输入两个数字,分别保存在 a 和 b中 2、如果 a 大于 b的话 ,则交换两个数字的位置 使用 短路&&,扩展赋值运算符,位运算 4、条件运算符(三目运算) 单目(一元)运算符 :++,--,! 双目(二元)...

    树状数组1:单点修改区间查询 模板

    第一行包含两个整数 $N$、$M$,分别表示该数列数字的个数和操作的总个数。 第二行包含 $N$ 个用空格分隔的整数,其中第 $i$ 个数字表示数列第 $i $ 项的初始值。 接下来 $M$ 行每行包含 $2$ 或 $4$个整数,表示一...

    (完整版)c语言程序设计编程题库.doc

    9. 编程求 1+(1+2)+…+(1+2+…+n),n 的值由键盘输入。 该程序使用了for循环结构,通过变量j和sum来计算每一项的值,并将其累加到sum中。最后,使用printf函数将sum的值输出。 10. 从键盘输入 10 个整数,统计...

Global site tag (gtag.js) - Google Analytics