【LeetCode】解题39:Combination Sum

本文详细解析了LeetCode第39题“组合总和”的解题思路,采用回溯算法和深度优先搜索策略,通过剪枝减少无用搜索,避免重复组合。文中提供了Java代码实现,并附有详细的流程说明。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Problem 39: Combination Sum [Medium]

Given a set of candidate numbers (candidates) (without duplicates) and a target number (target), find all unique combinations in candidates where the candidate numbers sums to target.

The same repeated number may be chosen from candidates unlimited number of times.

Note:

  • All numbers (including target) will be positive integers.
  • The solution set must not contain duplicate combinations.

Example 1:

Input: candidates = [2,3,6,7], target = 7,
A solution set is:
[
[7],
[2,2,3]
]

Example 2:

Input: candidates = [2,3,5], target = 8,
A solution set is:
[
[2,2,2,2],
[2,3,3],
[3,5]
]

来源:LeetCode

解题思路

基本思路为回溯算法,采用深度优先,并使用剪枝减少无用搜索。

  • 首先将候选数组按升序排序。
  • 每一轮循环从候选数组中选择一个数x加入组合,比较target'与x的大小,此处target'代表每一轮中新的目标值,根据比较结果分为三种情况:
    a. 如果target' - x = 0,说明组合中sum = target,将该种组合加入最终结果result列表里,并剪枝。
    b. 如果target' - x < 0,说明组合中sum > target,不能再加入任何数,也不能将x替换为更大的候选数,因此这里直接剪枝。
    c. 如果target' - x > 0,说明组合中sum < target,还可以继续深入搜索,更新target' = target' - x,进行递归搜索。
  • 注意:为了防止重复组合,每次选择的数x不能比已经存在于组合中的数小,因此递归时需要增加搜索范围参数,不能再次访问之前已经搜索完全的下标。

如下图所示,候选数组为[2,3,6,7],target为7,按深度优先策略,每一轮减去一个数观察剩余的目标值,小于或等于0时都要进行剪枝。其中带颜色的节点为叶节点,表示不再递归搜索,橙色的叶节点代表搜索路径上选择的数属于正确的组合。
回溯算法
要点:回溯算法剪枝

Solution (Java)

class Solution {
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        Arrays.sort(candidates);
        int N = candidates.length;
        if(N == 0) return result;
        List<Integer> comb = new ArrayList<Integer>();
        backtracking(candidates, 0, N, target, comb, result);
        return result;
    }
    private void backtracking(int [] candidates, int index, int N, int target, List<Integer> comb, List<List<Integer>> result){
        for(int i = index; i < N; i++){
            int next_target = target - candidates[i];
            if(next_target == 0){
                comb.add(candidates[i]);
                result.add(comb);
                return;
            }
            else if(next_target < 0){
                return;
            }
            else{
                List<Integer> next_comb = new ArrayList<Integer>(comb);
                next_comb.add(candidates[i]);
                backtracking(candidates, i, N, next_target, next_comb, result);
            }
        }
    }
}

修改过程

  • 没有在递归前创造新的列表空间,供后续选择不同的数,导致搜索过程中所有的数都加入了同一个组合。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值