LeetCode 1012 至少有 1 位重复的数字
给定正整数N,返回小于等于N且至少具有1位重复数字的正整数。当时没想到思路,只想到有重复数位的数不好算,但是不含有重复数字的数的个数可以算,后来看了一个人的解答,用数位dp+排列可以做出来。大致分为两部分,设这个数字有k位,第一部分计算是数字不到k位的数且这些数每一位的数字不相同,第二部分是计算k位数的满足上述条件的个数,具体可见代码。下图是一个计算的例子。
class Solution {
public:
int vis[10];
int ans=0;
int k=0;
int A(int i,int j)
{
int now=1,tmp=i;
for(int k=0;k<j;k++)
{
now*=tmp;
tmp--;
}
return now;
}
void dfs1(int now)
{
if(now<k-1)
{
ans+=9*A(9,now);
dfs1(now+1);
}
}
void dfs2(int now,vector<int>& v)
{
if(now==0)
{
int pos=k-now-1;
vis[v[pos]]=1;
ans+=(v[pos]-1)*A(9-now,k-1-now);
dfs2(now+1,v);
}
else if(now<k)
{
int pos=k-now-1;
int cnt=0;
for(int i=0;i<v[pos];i++)
if(vis[i])
cnt++;
ans+=(v[pos]-cnt)*A(9-now,k-1-now);
if(vis[v[pos]]==1) return ;
vis[v[pos]]=1;
dfs2(now+1,v);
}
if(now==k)
{
ans+=1;
}
}
int numDupDigitsAtMostN(int N) {
int tmp=N;
vector<int> v;
while(tmp)
{
v.push_back(tmp%10);
tmp/=10;
}
k=v.size();
dfs1(0);
dfs2(0,v);
ans=N-ans;
return ans;
}
};