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

这篇博客介绍了如何计算小于等于给定整数n的所有非负整数中数字1出现的次数。通过使用动态规划的方法,避免了重复计算,提高了效率。示例展示了对于n=13,输出为6。文章强调了记忆化的重要性,通过dp数组存储已计算过的状态,减少递归深度。代码中定义了一个名为`countDigitOne`的函数,实现了这一功能。
摘要由CSDN通过智能技术生成

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);
    }
};
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值