233. 数字 1 的个数--(每日一难phase2--day5)

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);
    }
};

你可能感兴趣的:(每日一难,算法,c++,leetcode)