剑指offer 计算1到n中所有1出现的次数
Posted duikerdd
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了剑指offer 计算1到n中所有1出现的次数相关的知识,希望对你有一定的参考价值。
如题,显而易见,我们可以依次计算所有数中的1来完成该功能:
int NumOfOneBetweenN(int n) { int sum = 0; for(int i=1;i<n;++i) sum += NumOfOne(i); return sum; } int NumOfOne(int i) { int sumi = 0; while(i) { if(i%10 == 1) sumi++; i/=10; } return sumi; }
时间复杂度为O(n*logn),效率不高。
那么,换一种思路考虑,计算每个位出现1的次数,当然,要先找到数学规律,这需要归纳推理:
设输入数字为n,1出现的次数为t,每一位出现的次数为ti.
n为个位数: 显而易见, n>=1,t=1;
n=0,t=0
n为十位数: n=13,个位出现1的情况:1,11, 十位出现1的情况:10,11,12,13 t=2+4=6;
n=23,个位出现1的情况:1,11,21, 十位出现1的情况:10~19 t=3+10=13;
n=33,个位出现1的情况:1,11,21,31, 十位出现1的情况: 10~19 t=4+10=14;
我们发现,当十位数>1,十位出现的次数固定: t10=10;
十位数=1,次数由个位大小决定: t10=t1+1;
个位数>1,次数由十位大小决定: t1=t10+1.
n为三位数: n=123,个位出现1的情况:1~91,101~121, 十位数出现1的情况: 10~19,110~119 , 百位出现1的情况: 100~123 t=13+20+24=57;
n=223,个位出现1的情况:1~91,101~191,201~221, 十位出现1的情况: 10~19,110~119,210~219, 百位出现1的情况: 100~199 t=23+30+100=153;
我们发现,十位的次数被高位影响,个位的次数也被高位影响,而百位和上面十位>1的情况一样,次数固定,=1的情况又会被低位影响
不妨,我们可以设一个五位数,我们要计算百位出现1的次数,那么可以把数字分成三部分,百位之前的高位,百位,百位之后的低位.
1.百位=0,百位出现1的次数只与高位有关.比如12013,百位出现1的情况:00100~00199,01100~01199...11100~11199.共1200个,也就是高位*本位固定后的次数,即12*100;
2.百位>1,百位出现1的次数只与高位有关.比如12313,百位出现1的情况,00100~00199,01100~01199...12100~12199,共1300个,也就是(高位+1)*1本位固定后的次数,即13*100;
3.百位=1,百位出现1的次数与高低位都有关.比如12113,百位出现1的情况,00100~00199...11100~11100,还有12100~12113,共1314个,也就是高位*本位固定后的次数+低位+1,即12*100+114
归纳: 某一位=0的时候,该位出现1的次数被高位决定,即 0该位~(高位-1)该位,共高位*该位固定数;
某一位>1的时候,该位出现1的次数被高位决定,即 0该位~高位该位,共(高位+1)*该位固定数;
某一位=1的时候,该位出现1的次数被高低位决定,即 0该位~(高位-1)该位 , 该位0~该位低位,共高位*该位固定数+低位+1;
本质上,其实只有两种情况: 1.ti=0||ti>1,可以被高位按固定次数列举完
2.ti=1,被高位按固定次数列举完之后,还有不足固定次数的,由低位决定
int NumOfOneBetweenN(int n) { int count = 0; int i = 1; int cur = 0,after = 0,before = 0; //循环处理每一位 while((n/i)!=0) { cur = (n/i)%10; before = n/(i*10); after = n - (n/i)*i; if(cur>1) count += (before+1)*i; else if(cur==0) count += before*i; else count += before*i + after + 1; i*=10; } return count; }
以上是关于剑指offer 计算1到n中所有1出现的次数的主要内容,如果未能解决你的问题,请参考以下文章
剑指offer 整数中1出现的次数(从1到n整数中1出现的次数)
剑指offer-整数中1出现的次数(从1到n整数中1出现的次数)
剑指offer-连续子数组的最大和,从1到n中1出现的次数,找第n个丑数
剑指offer 整数中1出现的次数(从1到n整数中1出现的次数)