给定正整数 N
,返回小于等于 N
且具有至少 1 位重复数字的正整数。
示例 1:
输入:20 输出:1 解释:具有至少 1 位重复数字的正数(<= 20)只有 11 。
示例 2:
输入:100 输出:10 解释:具有至少 1 位重复数字的正数(<= 100)有 11,22,33,44,55,66,77,88,99 和 100 。
示例 3:
输入:1000 输出:262
数位dp可以解决,不知道怎么写。
考虑一种通解的方法:原答案即N-没有重复的数字。关键是求没有重复的数字
对于位数比N小的情况,我们可以直接排列组合求。
对于与N相同的情况,我们从最高位根据数字的限制(limit)依此排列求解
int C(int m,int n) { int res=1; while(n) { res*=m; m--; n--; } return res; } int numDupDigitsAtMostN(int N) { vector<int>a; for(int x=N+1;x!=0;x/=10) a.push_back(x%10); int n=a.size(); reverse(a.begin(),a.end()); int res=0; for(int i=1;i<n;i++) res+=9*C(9,i-1); cout<<res<<endl; map<int,int>contain; for(int i=0;i<n;i++) { for(int j=i>0?0:1;j<a[i];j++) { if(contain[j]==0) res+=C(9-i,n-i-1); } if(contain[a[i]]>0) break; contain[a[i]]++; } return N-res; }
数位dp
int dfs(int t, bool up, bool ze, bool rp, int mask) { if (t < 0) return rp; if (!up && ~dp[t][ze][rp][mask]) return dp[t][ze][rp][mask]; int ret = 0, I = up ? a[t] : 9; rep(i, 0, I + 1) { bool nrp = rp; int nmas = mask; if (!(ze & i == 0)) { nrp |= mask >> i & 1; nmas |= 1 << i; } ret += dfs(t - 1, up & (i == I), ze & (i == 0), nrp, nmas); } if (!up) dp[t][ze][rp][mask] = ret; return ret; } int numDupDigitsAtMostN(int N) { memset(dp, -1, sizeof(dp)); int n = 0; while (N > 0) { a[n++] = N % 10; N /= 10; } return dfs(n - 1, 1, 1, 0, 0); }