
題目
給定一個按 非遞減順序 排列的數字數組 digits 。你可以用任意次數 digits[i] 來寫的數字。例如,如果 digits = ['1','3','5'],我們可以寫數字,如 '13', '551', 和 '1351315'。
傳回 可以生成的小于或等于給定整數 n 的正整數的個數 。
示例 1:
輸入:digits = ["1","3","5","7"], n = 100
輸出:20
解釋:
可寫出的 20 個數字是:
1, 3, 5, 7, 11, 13, 15, 17, 31, 33, 35, 37, 51, 53, 55, 57, 71, 73, 75, 77.
示例 2:
輸入:digits = ["1","4","9"], n = 1000000000
輸出:29523
解釋:
我們可以寫 3 個一位數字,9 個兩位數字,27 個三位數字,
81 個四位數字,243 個五位數字,729 個六位數字,
2187 個七位數字,6561 個八位數字和 19683 個九位數字。
總共,可以使用D中的數字寫出 29523 個整數。
示例 3:
輸入:digits = ["7"], n = 8
輸出:1
提示:
1 <= digits.length <= 9
digits[i].length == 1
digits[i] 是從 '1' 到 '9' 的數
digits 中的所有值都 不同
digits 按 非遞減順序 排列
1 <= n <= 109
題解
數位DP入門題:
題目要求傳回通過digits中的數字可以生成的<=正整數 n 的正整數個數
如:digits=["1","3"] n=52 答案是:1,3,11,13,31,3
将digits轉化為int數組類型的nums
記nums的長度為M,f(x)為nums能組成的位于[1,x]的數字個數,正整數x的長度為N
- 位數小于N的部分,這部分可通過計算得到,設此時數字的位數為k,那麼這部分個數為 ∑M^k(k∈[1,N-1])(nums數字可以複用)
-
位數等于N的部分,且最高位比x最高位小,這部分也可通過計算得到,設r為nums在x對應位能取到的數字最大索引
那麼x對應位可以取到digits[0,r],後面任意取都不會超過x,是以這部分個數為 (r+1)*M^(N-p),其中N-p表示目前位後面還有多少位數
-
位數等于N的部分,且最高位等于x最高位,最高位處保守隻能取到digits[0,r-1],這部分個數為 r*M^(N-p)
還沒完,還要累加最高位為digits[r]的情況,這取決于後面數字的貢獻數,參考下一位數屬于哪種情況
最後答案就是f(n)
/**
* @param {string[]} digits
* @param {number} n
* @return {number}
*/
var atMostNGivenDigitSet = function(digits, n) {
const s = n + '';
const K = s.length;
const dp = new Array(K+1).fill(0);
dp[K] = 1;
for(let i = K -1; i >= 0; --i) {
let si = s[i];
for(let j=0; j < digits.length; j++) {
if(digits[j] < si) {
dp[i] += Math.pow(digits.length, K-i-1)
} else if(digits[j] == si) {
dp[i] += dp[i+1];
}
}
}
for(let k=1; k< K; ++k) {
dp[0] += Math.pow(digits.length, k)
}
return dp[0]
};