Given a positive integer N, return the number of positive integers less than or equal to N that have at least 1 repeated digit.
Example 1:
Input: 20
Output: 1
Explanation: The only positive number (<= 20) with at least 1 repeated digit is 11.
Example 2:
Input: 100
Output: 10
Explanation: The positive numbers (<= 100) with atleast 1 repeated digit are 11, 22, 33, 44, 55, 66, 77, 88, 99, and 100.
Example 3:
Input: 1000
Output: 262
Note:
1 <= N <= 10^9
這道題給了一個正整數N,讓返回所有不大於N且至少有一個重復數字的正整數的個數,題目中給的例子也可以很好的幫助我們理解。要求的是正整數的位數上至少要有一個重復數字,當然最簡單暴力的方法就是從1遍歷到N,然后對於每個數字判斷是否有重復數字,看了一眼題目難度 Hard,想都不用想,肯定是超時的。這道題需要更高效的解法,首先來想,若是直接求至少有一個重復數字的正整數,由於並不知道有多少個重復數字,可能1個,2個,甚至全是重復數字,這樣很難找到規律。有時候直接求一個問題不好求,可以考慮求其相反的情況,至少有一個重復數字反過來就是一個重復數字都沒有,所以這里可以求不大於N且一個重復數字都沒有的正整數的個數,然后用N減去這個數字即為所求。好,接下來看怎么求,對於任意一個N,比如 7918,是個四位數,而所有的三位數,兩位數,一位數,都一定比其小,所以可以直接求出沒有重復數字的三位數,兩位數,和一位數。比如三位數,由於百位上不能有0,則只有9種情況,十位上可以有0,則有9種情況,個位上則有8種情況,所以就是 9*9*8。可以歸納出沒有重復數字的n位數的個數,最高位去除0還有9種,剩余的 n-1 位則依次是 9,8,7... 則后面的 n-1 位其實是個全排列,從9個數中取出 n-1 個數字的全排列,初中就學過的。這里寫一個全排列的子函數,求從m個數字中取n個數字的全排列,方便后面計算。算完這些后,還要來算符合題意的四位數,由於第一位是7,若千位上是小於7的數字(共有6種,千位上不能是0),則后面的百位,十位,個位又都可以全排列了,從9個數字中取3個數字的全排列,再乘以千位上小於7的6種情況。若當千位固定為7,則百位上可以放小於9的數字(共有8種,百位不能放7,但可以放0),則后面的十位和個位都可以全排列了,從8個數字種取出2個數字的全排列,再乘以百位上小於9的8種情況。需要注意的是,遍歷給定數字的各個位時,有可能出現重復數字,一旦出現了之后,則該 prefix 就不能再用了,因為已經不合題意了。所以要用一個 HashSet 來記錄訪問過的數字,一旦遇到重復數字后就直接 break 掉。最后還有一個小 trick 需要注意,由於N本身也需要計算進去,所以再計算的時候,使用 N+1 進行計算的話,就可以把N這種情況算進去了,參見代碼如下:
class Solution {
public:
int numDupDigitsAtMostN(int N) {
vector<int> digits;
unordered_set<int> visited;
for (int x = N + 1; x > 0; x /= 10) {
digits.insert(digits.begin(), x % 10);
}
int res = 0, len = digits.size();
for (int i = 1; i < len; ++i) {
res += 9 * A(9, i - 1);
}
for (int i = 0; i < len; ++i) {
for (int j = i > 0 ? 0 : 1; j < digits[i]; ++j) {
if (visited.count(j)) continue;
res += A(9 - i, len - i - 1);
}
if (visited.count(digits[i])) break;
visited.insert(digits[i]);
}
return N - res;
}
int A(int m, int n) {
return n == 0 ? 1 : A(m, n - 1) * (m - n + 1);
}
};
Github 同步地址:
https://github.com/grandyang/leetcode/issues/1012
類似題目:
Numbers At Most N Given Digit Set
參考資料:
https://leetcode.com/problems/numbers-with-repeated-digits/
