233. 数字 1 的个数
给定一个整数 n,计算所有小于等于 n 的非负整数中数字 1 出现的个数。
示例 1:
输入:n = 13
输出:6
示例 2:
输入:n = 0
输出:0
提示:
0 <= n <= 1e9
解析:
- 区间计数,仍然可以使用数位dp,将重复情况记忆化
- 例如:n=509,则2**与 3**,4**,情况都是一样的,可以重复利用
- 可以想象一下,如果没有限制,不用记忆化的做法:就是利用dfs枚举每一位上的数字(0-9),递归出口i==n,返回1的个数;
- 为何需要使用dp[i][cnt]记忆化?cnt代表前边位1的数量,前边位1的数量不同,结果也是不同的,例如110***和111***如果后边三位情况相同的话,显然两者1的数目应该不同。
代码:
class Solution {
public:
int countDigitOne(int m) {
string s = to_string(m);
int res=0;
int n=s.size();
int dp[n][n];
memset(dp,-1,sizeof(dp));
function<int(int,int,bool)> f = [&](int i,int cnt,bool isLimit){
if(i==n)
return cnt;
if(!isLimit&&dp[i][cnt]!=-1) return dp[i][cnt];
int res = 0;
int up = isLimit ? s[i] - '0':9;
for(int d = 0;d<=up;d++)
res += f(i+1,cnt+(d==1),isLimit&&d==up);
if(!isLimit) dp[i][cnt] = res;
return res;
};
return f(0,0,true);
}
};