[回溯法] -- 39 - 组合总和 - Java + Python

组合总和

给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。candidates 中的数字可以无限制重复被选取

说明:所有数字(包括 target)都是正整数。 解集不能包含重复的组合。

示例 1:

输入:candidates = [2,3,6,7], target = 7,
所求解集为:
[
  [7],
  [2,2,3]
]
示例 2:

输入:candidates = [2,3,5], target = 8,
所求解集为:
[
  [2,2,2,2],
  [2,3,3],
  [3,5]
]

提示:

  • 1 <= candidates.length <= 30
  • 1 <= candidates[i] <= 200
  • candidate中的每个元素都是独一无二的。 1 <= target <= 500

根据题目的描述可知,要求从候选数组中选择多个数字,使得它们之和等于给定的target。由于数组中元素无重复,因此需要考虑所有可能的组合形式,最后从中得到复合要求的结果。这是典型回溯思路的题目,解题之前首先需要明白回溯问题的三大核心要素:

  • 选择列表:当前已经选择的数字,且它们之和不应该大于target
  • 可选择列表:当前选择位置及之后位置数组的元素,由于题目中说明了数字可以无限制的重复选取,那么在选择完当前某位置元素后,下一次的选择仍然可以从当然位置开始,只要选择列表中的数字之和不大于target就可
  • 终止条件:选择列表中数字之和等于target,这里我们使用减法,每次选择一个合法的数字后,target就减去相应的值,最后只需判断target是否为0即可

同时在枚举的过程中还需要剪枝,下面的两种情况下需要进行剪枝操作:

  • 当前已经选到了数组的最后一个位置
  • 当前位置的数组元素比target还要大

如果明白了上述的算法流程后,根据回溯问题的解题思路,代码就好写了。

Java解题代码:

class Solution {
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<List<Integer>> results = new LinkedList<>();
        LinkedList<Integer> track = new LinkedList<>();

        Arrays.sort(candidates);
		if (candidates.length == 0 || candidates[0] > target){
            return results;
        }
        
        dfs(track, candidates, target, results, 0);

        results.forEach(System.out :: println);
        return results;
    }

    private void dfs(LinkedList<Integer> track, int[] candidates, int target, List<List<Integer>> results, int start) {

        if(target == 0){
            results.add(new LinkedList<>(track));
            return;
        }

        for (int i = start; i < candidates.length; i++) {
            if (i == candidates.length || candidates[i] > target){
                break;
            }

            // 做出选择
            track.add(candidates[i]);
            dfs(track, candidates, target - candidates[i], results, i);
            track.removeLast();
        }
    }
}

Python解题代码:

class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        if candidates == [] or min(candidates) > target: 
            return []
            
        length = len(candidates)
        results = []
        def dfs(candidates, target, track):
            if target == 0:
                results .append(track.copy())
                return 

            for i in range(len(candidates)):
                if i == length  or candidates[i] > target:
                    break
                    
                track.append(candidates[i])
                # python中数组的切片很方便,这里就不再记录当前选择的位置i
                dfs(candidates[i:], target - candidates[i], track)
                track.pop()

        candidates = sorted(candidates)
        dfs(candidates, target, [])
        
        return results 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值