题目
给定一个整数 n,计算所有小于等于 n 的非负整数中数字 1 出现的个数。
示例1:
输入:n = 13
输出:6
示例2:
输入:n = 0
输出:0
提示:
0 <= n <= 2 * 109
思路
动态规划
我首先想到的是枚举,但是毫无疑问超时了,数位dp看的是题解写的。
枚举
思路:dp[i]表示1~i
里已经出现的1的总数,状态方程:dp[i] = dp[i - 1] + 这个数中出现的1的次数
class Solution {
public:
int cacul_1(int num) {
int ans = 0;
while(num) {
ans += num % 10 == 1 ? 1 : 0;
}
return ans;
}
int countDigitOne(int n) {
vector<int>dp(n + 1,0);
for(int i = 1; i <= n; i++) {
dp[i] = dp[i - 1] + cacul_1(i);
}
return dp[n];
}
};
数位dp
这个思路是考虑每一个数位的情况,分别有0,1,其它三种情况。假设有220
,则个位出现1的数有:1,11,21....211
一共22个;如果是221
,则有1,11,21....211
+ 221
共23个;如果是223
则也是23个。。。解释起来好麻烦,建议看k神的讲解
class Solution {
public:
int countDigitOne(int n) {
long long base = 1;
int high = n,low = 0,cur = 0,ans = 0;
while(high != 0 || cur != 0) {
cur = high % 10;
high /= 10;
if(cur == 0) {
ans += high * base;
}else if(cur == 1){
ans += high * base + low + 1;
}else {
ans += (high + 1) * base;
}
low = cur * base + low;
base *= 10;
}
return ans;
}
};