698. 划分为k个相等的子集

题目 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后归还。

这道题适合用来练习回溯,用到的技巧如下:

  1. 总体上,使用回溯来解决,使用used数组标记访问路径
  2. 使用各种剪枝思路加速计算
  3. 用记忆化存储,防止重复状态。

记忆化存储相关代码如下:

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;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值