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