Leetcode 1012 至少有1位重复数字

题目描述:

  给定正整数 N,返回小于等于 N 且具有至少 1 位重复数字的正整数。

 

题解:

  求至少有1位重复数字的正整数有点复杂,转换一下思路,求小于等于N没有重复数字的正整数的个数。定义一个$dp[pos][status][bound]$(dp定义解释戳这里)。这里的$status$借用了一下状压的思想,记录的是在$pos$之前0~9出现的情况。例如在$pos$之前出现了0,1,3这三个数字的时候,$status = 2^{0} + 2^{1} + 2^{3} = 9$。在设计$status$状态转移的情况的时候,要注意一下前导零的判断。$bound$的状态转移方式见代码。

 

AC代码:

   

class Solution {
public:
    // 找出不存在重复的
    // sta 采用状压的思路 对0-9这10个数字0、1编码
    string num;
    int dp[10][1<<10][4];
    int dfs(string num,int pos,int sta,int bound)
    {
        int ans = 0;
        int l;
        if(pos >= num.size()) return 1;
        
        l = (bound & 2) ? num[pos]-'0':9;
        if(dp[pos][sta][bound] != -1) return dp[pos][sta][bound];
        for(int i=0;i<=l;i++)
        {
            if((sta>>i) & 1) continue;
            // cout << i <<endl;
            int tmp_sta = sta | (1 << i);
            int next_bound = (bound & 1? i == 0 :0) ^ (bound & 2? (i == l)<< 1 : 0);
            // 前导0的情况
            if(sta == 0 && i == 0) tmp_sta = 0;
            
            ans += dfs(num,pos+1,tmp_sta,next_bound);
        }
    
        dp[pos][sta][bound] = ans;
        return ans; 
    }

    int numDupDigitsAtMostN(int N) {
        num = "";
        int tmp = N;
        while(N)
        {
            num += N%10 + '0';
            N /= 10;
        }
        reverse(num.begin(),num.end());
        memset(dp,-1,sizeof(dp));
        // bound 0 1 2 3 其他 下界 上界 上下界交汇
        return tmp+1-dfs(num,0,0,3);
    }

};            

 

posted @ 2020-04-13 09:55  猪突猛进!!!  阅读(385)  评论(0编辑  收藏  举报