【leetcode】357. Count Numbers with Unique Digits

本文介绍了一种高效算法,用于计算区间[0,10^n)内所有位数字都不相同的数的数量。通过递推公式f(n)=9*9*8*...*(9-n+2)进行计算,并提供两种C++实现方案。

一、题目描述

Given a non-negative integer n, count all numbers with unique digits, x, where 0 ≤ x < 10n.

Example:
Given n = 2, return 91. (The answer should be the total numbers in the range of 0 ≤ x < 100, excluding[11,22,33,44,55,66,77,88,99])

Hint:

  1. A direct way is to use the backtracking approach.
  2. Backtracking should contains three states which are (the current number, number of steps to get that number and a bitmask which represent which number is marked as visited so far in the current number). Start with state (0,0,0) and count all valid number till we reach number of steps equals to 10n.
  3. This problem can also be solved using a dynamic programming approach and some knowledge of combinatorics.
  4. Let f(k) = count of numbers with unique digits with length equals k.
  5. f(1) = 10, ..., f(k) = 9 * 9 * 8 * ... (9 - k + 2) [The first factor is 9 because a number cannot start with 0].

题目解读:给出一个数n,求出区间[0, 10n) 中所有位数字都不相同的数共有多少个。


思路:一开始想到排列组合的解法去了,比如n=2时,在想区间[10, 100)中有多少个数不满足要求呢,只有两位比较好数,11,22,33,44,...,99共9个数....  后来发现找出的规律根本就不对。看了提示才发现直接从正面入手比较简单,假设现在在求n位的数满足条件的个数(不考虑n位以下的数),对于第一位有9种可能(因为第一位不能为0,否则就不是n位数是n-1位数了),第二位可以为0,但是不能和第一位相同,所有有9种选择,第三位是8种选择.....这样,就找出规律了f(1) = 10, f(n) = 9 * 9 * 8 * ... * (9-n+2),然后把 f(1) 到 f(n) 加上即可。


c++代码(0ms,16.19%)

class Solution {
public:
    int countNumbersWithUniqueDigits(int n) {
        //1、当n=0时,区间[0,1)
        if(n==0){
            return 1;
        }//if
        
        //2、当n=1时,区间[0,10)
        else if(n == 1){
            return 10;
        }//else if
    
        //4、当n>=2时,此时要去掉有重复数字的整数了
        else{   
            int result=91;
            for(int i=3; i<=n; i++){
            	int tmp=9;
                int flag=0;
                int res=1;
                for(int j=1;j<=i;j++){
                    res = res*tmp;
                    if(flag==0){
                        flag=1;
                    }else{
                        tmp--;
                    }
                }//for
                result+=res;
            }//for
            return result;
        }
    }
};


思路和运行时间一样,简洁点的代码如下:

class Solution {
public:
      int countNumbersWithUniqueDigits(int n) {  
        if(n==0) return 1;  
        if(n==1) return 10;  
        int val = 9, ans = 10;  
        for(int i = 2; i <= n; i++)  
        {  
            val *= (9-i+2);  
            ans += val;  
        }  
        return ans;  
    }  
};

代码2:

class Solution {
public:
    int countNumbersWithUniqueDigits(int n) {
        vector<int> dp(n+1, 0);
        if(n==0)
            return 1;
        dp[0]=1;
        for(int k=1;k<=n;k++){
            int num=9;
            int res=9;
            for(int i=2;i<=k;i++){
                res=res*num;
                num--;
            }
            dp[k]=res+dp[k-1];
        }//for
            
        return dp[n];
    }
};



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值