902. 最大为 N 的数字组合
我们有一组排序的数字 D,它是 {'1','2','3','4','5','6','7','8','9'} 的非空子集。(请注意,'0' 不包括在内。)
现在,我们用这些数字进行组合写数字,想用多少次就用多少次。例如 D = {'1','3','5'},我们可以写出像 '13', '551', '1351315' 这样的数字。
返回可以用 D 中的数字写出的小于或等于 N 的正整数的数目。
示例 1:
输入:D = [“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:
输入:D = [“1”,”4”,”9”], N = 1000000000
输出:29523
解释:
我们可以写 3 个一位数字,9 个两位数字,27 个三位数字,
81 个四位数字,243 个五位数字,729 个六位数字,
2187 个七位数字,6561 个八位数字和 19683 个九位数字。
总共,可以使用D中的数字写出 29523 个整数。
提示:
D是按排序顺序的数字'1'-'9'的子集。1 <= N <= 10^9
思路:
递推型写法:
- 先预处理
N,抠出每一位十进制数,假设共有n位 n - 1位数一定都小于N,每一位能选的个数有D.length个,用循环处理一下- 从最高位向最低位依次考虑,只有对应位在D中存在才会继续向低位考虑。
class Solution {public int atMostNGivenDigitSet(String[] digits, int v) {String num = Integer.toString(v);int n = digits.length, res = 0;for (int i = 1; i < num.length(); i++) {res += power(n, i);}boolean flag = true;for (int i = 0; i < num.length(); i++) {int x = num.charAt(i) - '0';int cnt = power(n, num.length() - 1 - i);int j = 0;while (j < n && digits[j].charAt(0) - '0' < x) {res += cnt;j++;}if (j < n && digits[j].charAt(0) - '0' == x)continue;else {flag = false;break;}}if (flag)res++;return res;}int power(int a, int b) {int res = 1;while (b > 0) {if ((b & 1) == 1)res *= a;a *= a;b >>= 1;}return res;}}
记忆化搜索:
模板:pos表示当前枚举到第几位,从高位向低位枚举,假设最低位为第0位lim表示高位的数是否贴合上界,1表示贴合上界lead表示高位是否全为0,1表示高位全为0
class Solution {List<Integer> list = new ArrayList<>();List<Integer> num = new ArrayList<>();int[] f = new int[10];public int atMostNGivenDigitSet(String[] digits, int n) {for (String s : digits) {list.add(Integer.parseInt(s));}while (n > 0) {num.add(n % 10);n /= 10;}Arrays.fill(f, -1);return dp(num.size() - 1, 1, 1);}int dp(int cur, int lim, int lead) {if (cur == -1)return lead == 0 ? 1 : 0;int ans = f[cur];if (lim != 1 && lead != 1 && ans != -1) return ans;ans = 0;int up = lim == 1 ? num.get(cur) : 9;if (lead == 1) ans += dp(cur - 1, 0, 1);for (int i : list) {if (i > up) break;if (lim == 1 && i == up)ans += dp(cur - 1, 1, 0);else ans += dp(cur - 1, 0, 0);}if (lim != 1 && lead != 1) f[cur] = ans;return ans;}}
