标签:比较 代码 总结 问题 开始 不同 等于 剑指offer valueof
题目:整数中1出现的次数(从1到n整数中1出现的次数)
求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。
思路分析
方法一:统计1-n之间1出现的次数,首先我们可以采用暴力解法直接数,从n到1,对于每个数都进行判断,如果含有1,则计数器加一。判断的方法是将每个数当成字符串,对于字符串的每一位是否为1进行判断即可.。
实现代码:
1 public class Solution { 2 public int NumberOf1Between1AndN_Solution(int n) { 3 int count=0; 4 while(n>0){ 5 String str=String.valueOf(n); 6 char [] chars=str.toCharArray(); 7 for(int i=0;i<chars.length;i++){ 8 if(chars[i]==‘1‘) 9 count++; 10 } 11 n--; 12 } 13 return count; 14 } 15 }
现在来分析一下上面代码的时间复杂度,总的外循环是从n到1,循环了n次,而内部的循环与n的位数有关。所以总的循环判断次数=(9)*1+(99-10+1)*2+(999-100+1)*3+(9999-1000+1)*4+...
总的时间复杂度是比较接近O(n)线性的,但是要大于O(N)
方法二:仔细观察也是可以找到规律的。
以n=12345为例子,12345=10000+2000+300+40+5,12345可以从每一位上单独进行分析,我们以i表示位数标识,以百位为例
i=100 此时a=12345/100=123 , b=12345%100=45 可以拆成前后两部分的,对于两部分可以先分开计算然后最后再相乘或相加(计数原理)
由于每一位上的情况都可以与百位上的情况相同,所以我们可以对以上规律进行总结归纳
如果百位上的数字大于等于2或是等于0,那么出现1的次数=(a+8)/10*100
(为什么加8,我们从上面可以看出大于等于2会比等于0在前面多出现一次1,为了得到对应的结果我们直接让大于等于2的向前进位后再取整,而等于0的由于其没有什么进位所以不会影响其结果)(如果题目由此变形一下,求2出现的次数,那么同理我们便可以划分为大于等于3的情况,等于2的情况,小于2的情况,此时可能就要加7)
如果百位上的数字等于1,那么总的次数由两部分组成,次数=a/10*100+(b+1)
让i从1开始逐步变为10,100,1000,。。。便可求出各个位上的1的数目,在循环的同时求和就行
代码如下:
1 public class Solution { 2 public int NumberOf1Between1AndN_Solution(int n) { 3 long count=0; 4 long i=1; 5 for(i=1;i<=n;i*=10){ 6 long a=n/i,b=n%i; 7 count=count+(a+8)/10*i+(a%10==1?1:0)*(b+1); 8 } 9 return (int)count; 10 } 11 }
剑指offer-整数中1出现的次数(从1到n整数中1出现的次数)
标签:比较 代码 总结 问题 开始 不同 等于 剑指offer valueof
原文地址:https://www.cnblogs.com/pathjh/p/9374772.html