Problem
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]
)
題意
給出一個非負整數n,計算所有滿足以下條件的x:
- 0 ≤ x < 10^n
- x中沒有重復數字(如121就不滿足,因為有兩個1)
分析
本題可以有兩種做法,一種是利用純數學方法,計算排列數即可;另一種是利用回溯的思想,有點類似于LeetCode# 526: Beautiful Arrangement,將不同的數字放置在不同的位置,求得滿足條件的放置方法數即可。
數學方法
題意可轉化為,在1個(n = 0, 1)或n個(n ≥ 2)位置上放置0-9這十個數字,是高中時候就學過的排列問題。
- 對于n=0的情況,滿足條件的數字只有
0
,只有1個; - 對于n=1的情況,滿足條件的數字有
0, 1, ..., 9
,有10個; - 對于n=2的情況,對于一位數,滿足條件的有10個;對于兩位數,問題變成了,從0-9這十個數字中挑出兩個分別放置在十位和個位,是A(2, 10);但是要注意0不能放在十位,所以要去掉A(1, 9)個數字,最后的結果:
result[2] = A(2, 10) - A(1, 9) + result[1]
- 對于n > 2的情況不再贅述。
回溯方法
//TODO
Code
數學方法
//Runtime: 0ms(精度不夠)
class Solution {
private:
vector<int> fac; //fac[i] = i!
vector<int> result; //result[i] = result of i
void _calFac(){
fac.resize(11);
fac[0] = 1;
for (int i = 1; i <= 10; i++)
fac[i] = i * fac[i - 1];
return;
}
void _calRst(int n){
result.resize(n + 1);
result[0] = 1;
for (int i = 1; i <= n; i++)
result[i] = fac[10] / fac[10 - i] - fac[9] / fac[10 - i] + result[i - 1];
return;
}
public:
int countNumbersWithUniqueDigits(int n) {
if (n > 10) return 0;
_calFac();
_calRst(n);
return result[n];
}
};
Backtracking
//TODO