题目 https://leetcode.cn/problems/partition-to-k-equal-sum-subsets/
解答 https://leetcode.cn/problems/partition-to-k-equal-sum-subsets/solution/by-lfool-d9o7/
这种题是经典的回溯题,因为难以用dp优化,转而用一维的记忆化存储。为什么能用回溯?我们看条件:
1 <= k <= len(nums) <= 16
0 < nums[i] < 10000
每个元素的频率在 [1,4] 范围内
k的取值较小,所以整形used的32位够用。而元素数少,所以回溯时从1迭代,且逐个用used判断即可。
- 如果k较大怎么办?可以用字符串,或者用数组表示一个int作位运算。
- 如果元素数较多怎么办?可以用LinkedList来存储剩余的数字,dfs时将选中的数字从第i位取出,并在dfs后归还。
这道题适合用来练习回溯,用到的技巧如下:
- 总体上,使用回溯来解决,使用used数组标记访问路径
- 使用各种剪枝思路加速计算
- 用记忆化存储,防止重复状态。
记忆化存储相关代码如下:
private HashMap<String, Boolean> memo = new HashMap<>();
...
String state = Arrays.toString(used);
if (memo.containsKey(state)) {
// 如果当前状态曾今计算过,就直接返回,不要再递归穷举了
return memo.get(state);
}
将当前的中间状态转为字符串储存效率太低。将其转为int更好,
private HashMap<Integer, Boolean> memo = new HashMap<>();
if (memo.containsKey(used)) {
// 如果当前状态曾今计算过,就直接返回,不要再递归穷举了
return memo.get(used);
}
for ...
// 球已装入,跳过
if (((used >> i) & 1) == 1) continue;
used |= 1 << i;
// 回溯
used ^= 1 << i;