描述
输入一个整数 n ,求1~n这n个整数的十进制表示中1出现的次数。
例如,输入12,1~12这些整数中包含1 的数字有1、10、11和12,1一共出现了5次。
思路:
1出现的总次数 = 个位上1的个数 + 十位上1的个数 + ……
故:简化问题,考虑第 i 位(从低到高)上1的个数:
令cur为当前位的数字,base为数量级,high为高位的数字,low为低位的数字,res为1出现的总次数,
若:
情况1、cur = 1,则固定第 i 位,满足小于等n的数均为符合条件的数,即res += high * base + low + 1;
情况2、cur ≠ 1,将该位退化到1,退化的时候考虑到低 i 位只有base个数第 i 含有1:
· cur = 0,则:high -= 1,res += base;
· cur > 1,则:low = 0,res += base - 1(不包含低位全0的情况);
此时,cur退化到1,再用情况1;
下面用n = 1214,1234分别对上述步骤进行说明,为简化步骤,只考虑十位:
1)对于n = 1214,cur = 1,base = 10,high = 12,low = 4,
因为cur = 1,所以固定该位,考虑小于n的个数,而此时:只要[high, low] <= 124,即为满足该条件的数([high, low]表示由高位、低位组成的数,相当于擦除该位),即res += 125;
2)对于n = 1234,cur = 3,base = 10,high = 12,low = 4,
因为cur = 3,所以要做退化处理:考虑低2位,只有10~19十个数在十位上有1,故只要low = 0、res += 9,十位便能退化到1,再用情况1,有:res += 121(总:res += (high + 1) * base = 130);
代码:
class Solution {
public:
int NumberOf1Between1AndN_Solution(int n) {
int cur = n % 10, high = n / 10, low = 0, base = 1, res = 0;
while (base <= n) {
if (cur == 0)
res += high * base;
else if (cur == 1)
res += high * base + low + 1;
else
res += (high + 1) * base;
base *= 10;
cur = high % 10;
high /= 10;
low = n % base;
}
return res;
}
};
参考:
https://leetcode-cn.com/problems/1nzheng-shu-zhong-1chu-xian-de-ci-shu-lcof/solution/mian-shi-ti-43-1n-zheng-shu-zhong-1-chu-xian-de-2/