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].

Backtracking

这个题目一看求方案个数, 用动态规划应该没有问题. 既然Hint中提到了Backtracking, 那就用backtracking也做了一遍。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
int total = 0;
public int countNumbersWithUniqueDigits(int n) {
boolean[] visited = new boolean[10];
backtracking(n, 0, 0, visited);
return total;
}
private void backtracking(int n, int count, int num, boolean[] visited) {
if (count == n) {
total++;
return;
}
for (int i = 0; i < 10; i++) {
if (!visited[i] || num == 0) {
num = num * 10 + i;
count++;
visited[i] = true;
backtracking(n, count, num, visited);
num = num / 10;
count--;
visited[i] = false;
}
}
}

Dynamic Programming

  • state: dp[i] means with i digits,the count of all numbers with unique digits.
  • function: dp[i] = dp[i - 1] + 9 * (9 * ... * (9 - n + 2)). 譬如说n = 3, 以非0开头,unique digdits组成的数的个数为9 * 9 * 8. 再加上以0开头的dp[2],就是所要答案 dp[3] = dp[2] + 9 * 9 * 8
  • init: dp[0] = 1
  • result: dp[n]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public int countNumbersWithUniqueDigits(int n) {
int[] dp = new int[n + 1];
dp[0] = 1;
for (int i = 1; i <= n; i++) {
dp[i] = dp[i - 1] + helper(i);
}
return dp[n];
}
private int helper(int n) {
int ans = 9;
for (int i = 9; i >= 9 - n + 2; i--) {
ans *= i;
}
return ans;
}

可以进行滚动数组优化

1
2
3
4
5
6
7
8
public int countNumbersWithUniqueDigits(int n) {
int[] dp = new int[2];
dp[0] = 1;
for (int i = 1; i <= n; i++) {
dp[i % 2] = dp[(i - 1) % 2] + helper(i);
}
return dp[n % 2];
}