233:Number of Digital One(hard)
描述:
给定整数N,统计1到N,设计函数countDigitOne(n),求出数字1出现的总次数。
例子:
N=3。 1,2,3。 return 1
N=11。 1,10,11。 return 3
思路:
1. 暴力枚举
-
计算给定数字含有1的数量方法,计算1的数量,使用整数分解,然后结果进行累加
-
弊端:
- 算法复杂度:对于长度为Len的数字n,时间复杂度为O(len≈log n)—>总复杂度O(nlog n)
-
代码实现:
-
class Solution{ public: int countDigitOne(int n){ int sum = 0; int factor = 1; for(int i =1;i<=n;i++){ int tmp = i; while(tmp/10 != 0) //1. tmp>0 { if(tmp%10 = 1) //2.tmp %10 ==1 sum++; tmp = tmp/10; //3 tmp /= 10 }//数字i拆分后计算1的数量 } return sum; } };
2. 统计的方法
-
找规律:按数字的每一位(个、十、百……)统计,例如
数字 计算 每一位1的个数 16135 0-1612+1 1614 16135 000-160*10+10 1620 16135 00-16*100+35 1635 16135 0-0*1000+1000 2000 16135 6135 6135 得到规律:第i位上1的个数:
n / 1 0 ( i + 1 ) ∗ 1 0 i + x n/10^{(i+1)}*10^{i}+x n/10(i+1)∗10i+x
其中,x的取值,与当前数字位的取值有关,当大于1时,可以加上
x = { 1 0 i , 当 前 为 大 于 1 0 , 当 前 位 位 0 除 以 10 取 余 数 + 1 , 当 前 位 为 1 x = \begin{cases} 10^{i}, 当前为大于1\\0,当前位位0\\除以10取余数+1,当前位为1 \end{cases} x=⎩⎪⎨⎪⎧10i,当前为大于10,当前位位0除以10取余数+1,当前位为1
时间复杂度:O(log n) ,对于每一个数字,按位统计 -
代码实现
-
class Solution{ public: int countDigitOne(int n){ long long factor = 1; //数位 int total_sum = 0; //1的总和 while(factor <= n){ int curr_num = (n/factor) %10; int higher_num = n/(factor*10); //提取n中当前位置数字和更高位数字 total_sum += higher_num*factor; //1. if(curr_num == 1) { total_sum += curr_num +1; //2. n%factor + 1;加余数 } else if(curr_num>1){ total_sum += factor; //3. } factor *= 10; } return total_sum; } }