输入一个整数 n ,求1~n这n个整数的十进制表示中1出现的次数。
例如,输入12,1~12这些整数中包含1 的数字有1、10、11和12,1一共出现了5次。
示例 1:
输入:n = 12
输出:5
示例 2:
输入:n = 13
输出:6
限制:
1 <= n < 2^31
解:
eg: 对于整数64012
思路:分别计算,0~64012,所有个位出现的1的次数 + 十位出现的1的次数 + ……
将一个数分为high cur low ,
640 1 2,计算十位出现1的次数;
对于high∈[0,639],十位为1的数为10~19,1共64010次;
对于high = 640,十位为1的数字10,11,12,1共3次;
故总值为64010 + 2 + 1。
64 0 12,计算百位出现的1的次数;
对于high∈[0,63],百位为1的数为100~199,1共64100次;
对于high = 64,不存在百位为1的数字;
故总值为64100。
6 4 012,计算千位出现的1的次数;
对于high∈[0,5],千位为1的数为1000~1990,1共6*1000次;
对于high = 6,千位为1的数为1000~1990,1共1000次;
故总值为(6+1)*100。
总结:
当cur = 0,cnt = high*(10^位数)
当cur = 1,cnt = high*(10^位数) + low + 1
当cur > 1,cnt = (high + 1)(10^位数)
时间复杂度分析
循环内部时间复杂度为O(1),循环次数为n的十进制位数,log(10)n,故时间复杂度为O(logn)。
class Solution {
public:
int countDigitOne(int n) {
int res = 0;
int low = 0,high = n/10,cur = n%10;
unsigned int digit = 1;//(10^位数,2的31次方是十位数,故digit最大为10^10,int型会溢出)
while(high != 0 || cur != 0)
{
if(cur == 0) res += high*digit;
else if(cur == 1) res += high*digit + low + 1;
else res += (high + 1)*digit;
low += cur*digit;
digit *= 10;
cur = high%10;
high /= 10;
}
return res;
}
};