We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
类似的题目有:
参考资料:
先决题目条件: 给一个数字n,这个数字范围大到10^9,然后计算0或1到n之间所有数字的位的特性;如果要求在[low, high]的数,就求两次,再用减法
方法: 记忆化搜索。对每位进行DFS,同时为了减少重复计算,用二维数组dp记录每个状态,dp[i][j]表示第i位时当前状态为j(mask或者其他)时的数目。参数same/limit代表是否跟数字n每位相同,循环每位的时候也要考虑最大值。
关键: 因为数字范围是10^9非常大,所以关键是利用条件进行状态压缩,建立缓存,避免重复计算。常见的有:对位压缩mask、对上一个数字压缩、甚至只对数量压缩。
记忆化搜索中缓存的定义与递推中的缓存相比,顺序是反过来的。
答题模版 以No.1012为例
class Solution { int[][] dp; public int numDupDigitsAtMostN(int n) { String str = String.valueOf(n); int len = str.length(); dp = new int[len][1 << 10]; return n + 1 - dfs(str, 0, 0, true); } private int dfs(String str, int pos, int mask, boolean same) { if (pos == str.length()) { return 1; } if (!same && dp[pos][mask] != 0) { return dp[pos][mask]; } int res = 0; int max = same ? str.charAt(pos) - '0' : 9; for (int k = 0; k <= max; ++k) { if ((mask & (1 << k)) != 0) { continue; } res += dfs(str, pos + 1, mask == 0 && k == 0 ? 0 : (mask | (1 << k)), same && k == max); } if (!same) { dp[pos][mask] = res; } return res; } }
这次是记录奇偶之差和余数。
做题的时候思路卡在余数这里,虽然看到数据大小有猜想是通过余数实现。但为什么可以**(mod + 10 + i) % k**呢?
class Solution { public int numberOfBeautifulIntegers(int low, int high, int k) { int a = cal(high, k), b = cal(low - 1, k); return a - b; } private int cal(int hi, int k) { String s = String.valueOf(hi); int n = s.length(); Map<String, Integer> memo = new HashMap<>(); return dfs(0, 0, 0, true, false, n, memo, s, k); } private int dfs(int pos, int diff, int mod, boolean isLimit, boolean isNum, final int n, final Map<String, Integer> memo, String s, final int k) { if (pos == n) { return (isNum && (diff == 0) && (mod == 0)) ? 1 : 0; } String key = pos + "_" + diff + "_" + mod; if (!isLimit && isNum && memo.containsKey(key)) { return memo.get(key); } int ans = 0; if (!isNum) { ans = dfs(pos + 1, diff, mod, false, false, n, memo, s, k); } int mx = isLimit ? s.charAt(pos) - '0' : 9; for (int i = isNum ? 0 : 1; i <= mx; i++) { ans = ans + dfs(pos + 1, i % 2 == 0 ? diff - 1 : diff + 1, (mod * 10 + i) % k, isLimit && i == mx, true, n, memo, s, k); } if (!isLimit && isNum) { memo.put(key, ans); } return ans; } }
The text was updated successfully, but these errors were encountered:
No branches or pull requests
模版题:数位DP
类似的题目有:
参考资料:
先决题目条件:
给一个数字n,这个数字范围大到10^9,然后计算0或1到n之间所有数字的位的特性;如果要求在[low, high]的数,就求两次,再用减法
方法:
记忆化搜索。对每位进行DFS,同时为了减少重复计算,用二维数组dp记录每个状态,dp[i][j]表示第i位时当前状态为j(mask或者其他)时的数目。参数same/limit代表是否跟数字n每位相同,循环每位的时候也要考虑最大值。
关键:
因为数字范围是10^9非常大,所以关键是利用条件进行状态压缩,建立缓存,避免重复计算。常见的有:对位压缩mask、对上一个数字压缩、甚至只对数量压缩。
记忆化搜索中缓存的定义与递推中的缓存相比,顺序是反过来的。
答题模版
以No.1012为例
2827. Number of Beautiful Integers in the Range
这次是记录奇偶之差和余数。
做题的时候思路卡在余数这里,虽然看到数据大小有猜想是通过余数实现。但为什么可以**(mod + 10 + i) % k**呢?
The text was updated successfully, but these errors were encountered: