leetcode2376

统计特殊整数

题意:给定一个整数n,统计[1,n]这个区间之间每一位数都不同的整数共有多少个。

思路:每一位共有10中选择,如果暴力搜索的话那么就是10^n,这样的复杂度显然不能接受。

一种好的方法是采用数位dp。数位dp通常用于求解一个区间内满足条件的数的总数,这个区间通常情况下非常大,不适合暴力搜索。

用一个状态位status来表示0-9之间的数字是否被选中,例如 1100000001,表示0、8、9这三个数字已经被选中,所以要有一个参数pos来记录当前的位置。这两个参数就帮助我们记忆化了之前搜索过的。

现在我们还需要第3个参数limit,这个参数表示当前位可选的数字是否收到上一位的限制,例如,对于数字1234,如果第3位选择的数字是3,那么第4位可选的数字就是0-4,否则就是0-9。

最后,在一些题目中可能会出现前导0的限制,也就是说数字不能以0开头。对于这种情况,可以单独处理。

class Solution {
public:
    /* 
    数位dp
     */
    vector<int> num;
    int dp[11][1 << 10];
    int len;
    int countSpecialNumbers(int n) {
        memset(dp, -1, sizeof(dp));
        len = n;
        while(n){
            num.push_back(n%10);
            n/=10;
        }
       
        return dps(num.size()-1, 0, true);
    }
    int dps(int pos, int status, bool limit){
        if(pos < 0) return 1;
        if(!limit && dp[pos][status]!=-1) return dp[pos][status];

        int res = 0;
        int mx = limit ? num[pos] : 9;

        for(int i = 0; i <= mx; i++){
            if(pos == 0 && status == 0 && i ==0) continue;  //去除一直为0的情况
            else if(status == 0 && i == 0)   //单独处理前导0,不加入status中
                res += dps(pos-1, status, limit && num[pos] == i);
            else if(! (status & (1 << i)) )
                res += dps(pos-1, status | (1 << i), limit && i == num[pos]);
        }
        if(!limit) dp[pos][status] = res;
        return res;


    }
};

数位dp的时间复杂度等于 状态个数*转移个数,对于本题就是 O(2^n * n),n是数组num的长度。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值