LeetCode 39. Combination Sum 题解

这题有几个主要的点,

首先,题目要求输出所有的组合数,而不是数据所有组合总的个数,如果是求个数用动态规划更好解决。但是要输出所有的组合数的话使用回溯法更容易处理。

其次,题目要求不能包含有重复的组合,这是解决这个题目的一个难点。

最后,保存解决方案的时候要注意Java里List的浅拷贝和深拷贝,不然浅拷贝最后得到空值。

解法:

其实回溯的方法还是比较简单的,为了后面处理的适合容易去重和剪枝优化,首先需要对数组进行排序。

排序后,从第一个元素开始搜索,可以重复添加元素,一直累加,并保存每个值到List。

如果这个和等于target,就保存这个List,然后继续回溯。

如果和大于了target则直接返回。

这里去重的关键一步是回溯的时候,在选择下一个值时,循环不能从0开始,否则会出现重复的情况。

这时应该跳过之前已经循环过的值,而寻找后面比当前值更大的值。

List<List<Integer>> res = new ArrayList<>();
	public List<List<Integer>> combinationSum (int[] candidates, int target) {
		Arrays.sort(candidates);
		int sum = 0;
		 if(candidates == null || candidates.length == 0)
	            return res;
		List<Integer> list = new ArrayList<>();
		trace(candidates,target,sum,list,0);
		return res;
    }
	
	/**
	 * 回溯,help(candidates, target-candidates[i], res, path, i);使用减法的比加法的用时更少
	 */
	public void trace(int[] candidates, int target , int sum , List<Integer> list,int start){
		if(sum > target){
			return;
		}
		if(sum == target){
			res.add(new ArrayList<>(list));
			return;
		}
		// 去重的关键在于j的值不能从0开始,而应该是start开始。
		for(int j = start; j < candidates.length;j++){
			if(candidates[j] > target)
                break;
			list.add(candidates[j]);
			trace(candidates,target,sum + candidates[j],list,j);
			list.remove(list.size() - 1);
		}
		
	}

比较一下

int[] candidates = {2,3,6,7};

target = 7时去重和没去重的回溯的区别,没去重时:

[2, 2, 2, 2]
[2, 2, 2, 3]
[2, 2, 2, 6]
[2, 2, 2, 7]
[2, 2, 3]
[2, 2, 6]
[2, 2, 7]
[2, 3, 2]     // 最后2比3小
[2, 3, 3]
[2, 3, 6]
[2, 3, 7]
[2, 6]
[2, 7]
[3, 2, 2]    // 中间2比3小
[3, 2, 3]    // 中间2比3小
[3, 2, 6]    // 中间2比3小
[3, 2, 7]    // 中间2比3小
[3, 3, 2]    // 最后2比3小
[3, 3, 3]
[3, 3, 6]
[3, 3, 7]
[3, 6]
[3, 7]
[6, 2]       // 最后2比6小
[6, 3]       // 最后3比6小
[6, 6]
[6, 7]
[7]

去重后:

[2, 2, 2, 2]
[2, 2, 2, 3]
[2, 2, 2, 6]
[2, 2, 2, 7]
[2, 2, 3]
[2, 2, 6]
[2, 2, 7]
[2, 3, 3]
[2, 3, 6]
[2, 3, 7]
[2, 6]
[2, 7]
[3, 3, 3]
[3, 3, 6]
[3, 3, 7]
[3, 6]
[3, 7]
[6, 6]
[6, 7]
[7]

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值