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;
    }
};
posted @ 2020-05-01 17:42  South1999  阅读(164)  评论(0编辑  收藏  举报