357. Count Numbers with Unique Digits (Medium)

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

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 $$10^n$$.
  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].

Solution 1: Math + DP

Time Complexity: $$O(1)$$ 0ms

这道题让我们找一个范围内的各位上不相同的数字,比如123就是各位不相同的数字,而11,121,222就不是这样的数字。那么我们根据提示中的最后一条可以知道,一位数的满足要求的数字是10个(0到9),二位数的满足题意的是81个,[10 - 99]这90个数字中去掉[11,22,33,44,55,66,77,88,99]这9个数字,还剩81个。通项公式为f(k) = 9 9 8 * ... (9 - k + 2),那么我们就可以根据n的大小,把[1, n]区间位数通过通项公式算出来累加起来即可,参见代码如下:

int countNumbersWithUniqueDigits(int n) {
    if (n == 0) return 1;
    int res = 10, f = 9, k = 9;
    n = min(n, 10);
    for (int i = 2; i <= n; ++i) { // num with i digits
        f *= k; --k;
        res += f;
    }
    return res;
}

Solution 2: BackTracking

Time Complexity: $$O(10!)$$ 206ms

最后我们来看题目提示中所说的回溯的方法,我们需要一个变量used,其二进制第i位为1表示数字i出现过,刚开始我们遍历1到9,对于每个遍历到的数字,现在used中标记已经出现过,然后在调用递归函数。在递归函数中,如果这个数字小于最大值,则结果res自增1,否则返回res。然后遍历0到9,如果当前数字没有在used中出现过,此时在used中标记,然后给当前数字乘以10加上i,再继续调用递归函数,这样我们可以遍历到所有的情况,参见代码如下:

class Solution {
public:
    int countNumbersWithUniqueDigits(int n) {
        if (n > 10) countNumbersWithUniqueDigits(10);
        int max = pow(10, n), res = 1; // when num = 0, res = 1
        for (int i = 1; i < 10; ++i) { // first digit does not include 0
            res += search(i, max, 1 << i);
        }
        return res;
    }

    int search(int pre, int max, int used) {
        int cnt = 0;
        if (pre < max) ++cnt;
        else return cnt;

        for (int i = 0; i < 10; ++i) {
            if ((used & (1 << i)) == 0) {
                used |= (1 << i);
                cnt += search(10*pre + i, max, used);
                used &= ~(1 << i);
            }
        }
        return cnt;
    }
};

results matching ""

    No results matching ""