Leetcode 剑指 Offer 43. 1~n 整数中 1 出现的次数
题目
输入一个整数 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
思路
- 我们要明确出现1的次数 = 每个位上面出现1的次数的和
- 现在我们以十位为例子, 说明下面的3种情况:
- 十位是1, 比方说111, 以十位作为分割线, 高位1, 低位1, 现在看小于等于111的十位为1的有多少个, 高位取[0, 1), 低位可以取[0,9], 也就是1 * 10 = 10, 高位取1, 低位可以取[0, 1], 也就是1 * (1 + 1), 总共为12个, 我们验证一下:小于等于111的且十位为1的有10, 11, 12, 13, 14,15,16,17,18,19,110,111, 正确
- 十位小于1即十位为0, 比方说101, 同样以十位分割, 高位1, 低位1, 可以发现, 此时高位只可取[0, 1), 低位可以取[0,9], 也就是1 * 10 = 10个
- 十位大于1, 比方说121, 也以十位分割, 高位1, 低位1, 此时高位可以取[0,1], 低位可以取[0,9], 也就是(1 + 1) * 10 = 20个
代码 —— c++
class Solution {
public:
int countDigitOne(int n) {
int res = 0;
for (long long m = 1;m <= n;m *= 10) {
int high = n / m / 10;
int low = n % m;
int cur = n / m % 10;
if (cur == 1) {
res += high * m + 1 * (low + 1);
} else if (cur < 1) {
res += high * m;
} else {
res += (high + 1) * m;
}
}
return res;
}
};