<LeetCode OJ> 357. Count Numbers with Unique Digits

Total Accepted: 450  Total Submissions: 1077  Difficulty: Medium

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

Credits:
Special thanks to @memoryless for adding this problem and creating all test cases.

Subscribe to see which companies asked this question

Show Tags

分析与翻译:

给定一个非负整数 n,计算所有各位数字均不同的数字x的个数,其中0 ≤ x < 10^n。
例子:

给定n=2,答案为91.因为在0-100的数字中除了11,22,33,44,55,66,77,88,99其他所有数各位均不同。
提示:
1)一个直接的办法是使用回溯法。
2)回溯应当包含三个状态(当前数字,得到该数字需要的步数,以及一个比特掩码用来表示当前已经访问过哪些位)。从状态(0,0,0)开始,并计算直到10^n为止的有效数字个数。
3)这个问题也可以使用动态规划方法与一些组合的知识来求解。
4)定义子问题f(k) :长度为k时各位均不同数字的个数。
5)f(1) = 10, ..., f(k) = 9 * 9 * 8 * ... (9 - k + 2) [首个因数是9,因为数字不能从0开始].

分析开始:找规律

既然说可以用动态规划,并且子问题都给你定义好了,那么这个问题就简单了!

n=1时,一位数A,[0,10)显然10个,
n=2时,两位数AB,[0,100),第一位A有9种选择(不能为0),第二位B有9中选择,81种,再加一位的10种,共91种
n=3时,三位数ABC,[0,1000),同理,A有9种可能,B有9种,C有8种...9*9*8+81+10=739

...

所以f(k) = 9 * 9 * 8 * ... (9 - k + 2),我们所做工作只是累加f(1)到f(n)即可,分析完毕。

代码一目了然,不言而喻

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

简写代码:

class Solution {
public:
    int countNumbersWithUniqueDigits(int n) {
        if ( n < 0 )  
            return 0;
        int result = 1;
        int multiplier = 9;
        n = min(n, 10);
        for (int i = 1; i <= n; i++) {
            result += multiplier;
            multiplier *= (i > 9 ? 0: (10 - i));
        }
        return result;
    }
};





注:本博文为EbowTang原创,后续可能继续更新本文。如果转载,请务必复制本条信息!

原文地址:http://blog.csdn.net/ebowtang/article/details/51658886

原作者博客:http://blog.csdn.net/ebowtang

本博客LeetCode题解索引:http://blog.csdn.net/ebowtang/article/details/50668895

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值