试题请参见: https://leetcode.com/problems/number-of-digit-one/
题目概述
Given an integer n, count the total number of digit 1 appearing in all non-negative integers less than or equal to n.
For example:
Given n = 13,
Return 6, because digit 1 occurred in the following numbers: 1, 10, 11, 12, 13.
解题思路
题目乍一看非常简单.
最低级的方法就是从1-n循环, 累加每一个数字中1的个数. 于是妥妥的TLE.
然后就看到了某大神的思路:
每10个数, 有一个个位是1; 每100个数, 有10个十位是1; 每1000个数, 有100个百位是1.
因此可以使用一个循环, 计算每一位(个位,十位, 百位)上1的总个数.
举个栗子:
- 对于n=3141092, a = 31410, b = 92. 计算百位上1的个数应该为 3141 x 100 次;
- 对于n=3141192, a = 31411, b = 92. 计算百位上1的个数应该为 3141 x 100 + (92 + 1) 次;
- 对于n=3141592, a = 31415, b = 92. 计算百位上1的个数应该为 (3141 + 1) x 100次;
以上三个栗子分别代表了三种情况, 即百位上的数值x == 0, x == 1和x >= 2的情况.
因此对于某一位(个位,十位, 百位)上1的总个数可以使用如下公式:
(n / m + 8) / 10 * m + (n / m % 10 == 1) * (n % m + 1)
其中 m = 10, 100, 1000, etc.
遇到的问题
循环变量i必须为64位整型类型, 否则会溢出.
源代码
#include <iostream>
class Solution {
public:
int countDigitOne(int n) {
int numberOfOne = 0;
for ( long long i = 1; i <= n; i *= 10 ) {
int a = n / i, b = n % i;
numberOfOne += ( a + 8 ) / 10 * i;
if ( a % 10 == 1 ) {
numberOfOne += b + 1;
}
}
return numberOfOne;
}
};
int main() {
int n = 0;
Solution s;
std::cin >> n;
std::cout << s.countDigitOne(n) << std::endl;
return 0;
}