组合总和(combinationSum)以及List的add()方法的问题

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

candidates 中的数字可以无限制重复被选取。

说明:

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

思路:用回溯法,把candidates中的数先加一下,如果不行则回溯。

设计递归函数combination,根据JAVA参数引用传递的特点,实现遍历。

我的代码:

public class CombinationSum {
	public List<List<Integer>> combinationSum(int[] candidates, int target) {
		List<List<Integer>> res = new ArrayList<>();
		if(candidates.length == 0
				||(candidates.length == 1 && candidates[0]>target))
			return res;
        Arrays.sort(candidates); //排序
        combination(res, target, 0, null, candidates);
		return res;
    }
	private void combination(List<List<Integer>> res,int target,int i,List<Integer>tmp,int[] candidates) {
		if(target == 0) {
            //此处一定要新建一个List再添加到res中,因为java的list.add()
            //方法是传递的引用!!!如果直接将tmp加进去后续对tmp的add、remove操作
            //会影响到res中的值,使得结果不对!!!
			List<Integer> tmp1 = new ArrayList<>(tmp);
			if(!res.contains(tmp1))
				res.add(tmp1);
			//找到满足条件的解,回溯找其他解
			tmp.remove(tmp.size()-1);
			return;
		}else if (target<0) {
			//不满足条件,且子节点必然也不满足条件,回溯
			tmp.remove(tmp.size()-1);
			return;
		}
		for(;i<candidates.length;i++) {
			if(tmp == null)tmp = new ArrayList<>();
			//由于candidates是排好序的,如果出现比target大,则后续都剪掉(相当于剪枝)
			if(candidates[i]>target)break; 
			tmp.add(candidates[i]);
			combination(res, target-candidates[i], i, tmp, candidates);	
		}
		//能够执行到这里说明这个节点解空间的所有子树都遍历过并且没有找到满足条件的解,需要回溯
		if(!tmp.isEmpty())
			tmp.remove(tmp.size()-1);
	}

	public static void main(String[] args) {
		System.out.println(new CombinationSum().combinationSum(new int[] {
				2,3,6,7
		}, 7).toString());
		System.out.println(new CombinationSum().combinationSum(new int[] {
				2,3,5
		}, 8).toString());
	}
}

另外一种写法:也是回溯法。

//count用来计数每个数记录了几次
private void search(int[] candidates, int target, int[] count, List<List<Integer>> res, int n) {
        if(target == 0) {
            List<Integer> list = new ArrayList<Integer>();
            for(int i = 0; i <= n; i++) {
                for(int j = 0; j < count[i]; j++) {
                    list.add(candidates[i]);
                }
            }
            res.add(list);
        }
        
        if(n == candidates.length || target < candidates[n])
            return;
        
        search(candidates, target, count, res, n + 1);
        count[n]++;        
        search(candidates, target - candidates[n], count, res, n);
        count[n]--;
    }
    
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        if(candidates == null || candidates.length == 0) {
            return new ArrayList<List<Integer>>();
        }
        
        Arrays.sort(candidates);
        
        List<List<Integer>> res = new ArrayList<List<Integer>>();
        int[] count = new int[candidates.length];
        search(candidates, target, count, res, 0);
        return res;
    }

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值