LeetCode:40 组合总和2(Golang)

LeetCode:40 组合总和2(Golang)

题目描述

给你一个整数数组 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。candidates 中的每个数字在每个组合中只能使用 一次 。注意:解集不能包含重复的组合。

示例 1:
输入: candidates = [10,1,2,7,6,1,5], target = 8,
输出:
[[1,1,6],[1,2,5],[1,7],[2,6]]

分析

借鉴上一题的官方解答,把组合问题看作一棵树然后DFS遍历确实是个经典的思路(比我的砝码模型好使)。本题相较于上一题区别在于:
1.每个 candidate 只能用一次;
2.整数集合 candidates 包含重复数,但结果集内不能包含重复的组合;

针对第1条,每个candidate只能用一次:这其实会让我们的组合树变得更简单,树的高度(迭代次数)不会超过len(candidates);
针对第2条:整数集合 candidates 包含重复数,但结果集内不能包含重复的组合;

首先,我们需要先对 candidates 排序,让相同的 candidate 相邻,并且组合结果都是按从小到大排列,否则 [1,2,2] 和 [2,1,2] 是重复组合,由于二者内部排列顺序不同,我们不好去重,所以让它们都变成 [1,2,2]。

其次,我们可以完全 DFS 遍历这棵树,然后使用哈希表对结果进行去重。是一种办法,但本题提交会超时(因为 candidates 的边缘案例)。优化:假如 candidates 是 [1,2,2,5,…] ,观察遍历过程,索引为 1 的组合即:[1,2(索引1),…] )已经包含了索引为 2 的所有可能的组合(即:[1,2(索引2),…] )。所以优化的办法是,同一层级中,遇见相同的candidate,只沿第一个进行 DFS 遍历形成子树,其余重复candidate跳过,此称为大剪枝(即剪去重复candidate为根的子树)

代码

func combinationSum2(candidates []int, target int) (res [][]int) {
   sort.Ints(candidates)
   remain := target
   comb := []int{}
   dfs := func(int) {}
   dfs = func(idx int) {
      if idx >= 0 {
         comb = append(comb, candidates[idx])
         remain -= candidates[idx]
         //fmt.Println("comb:", comb)  // test
      }
      if remain < 0 { // 小剪枝
         return
      }
      if remain == 0 {
         res = append(res, append([]int{}, comb...))
      }
      for i := idx + 1; i <= len(candidates)-1; i++ {
         if i > idx+1 && candidates[i-1] == candidates[i] { // 大剪枝
            continue
         }
         dfs(i)
         remain += comb[len(comb)-1]
         comb = comb[:len(comb)-1]
      }
   }
   dfs(-1)
   return
}
  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值