组合总和Ⅱ(DFS实现)

题目

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

注意:
1、candidates 中的每个数字在每个组合中只能使用一次;
2、所有数字(包括目标数)都是正整数;
3、解集不能包含重复的组合。

示例:
输入: candidates = [10,1,2,7,6,1,5], target = 8,
所求解集为:
[ [1, 7], [1, 2, 5], [2, 6], [1, 1, 6] ]

注意点

1、排序和去除元素比目标值大的比较(if(arr[i] > target) break;),是为了加快搜索;
2、当target等于0时,lists必须添加拷贝list的值(lists.add(new LinkedList(list))),如果直接使用lists.add(list)会导致返回结果为null,因为lists集合存放的是引用数据类型的地址,回溯时会将lists中的list清空;
3、i > start && arr[i] == arr[i - 1]是为了保证每一层元素不重复(解集不能包含重复的组合)。
4、思路:

  • 参考:组合总和(DFS实现)
  • 不同点:在于每个元素只能使用一次,有重复元素,且结果不可以重复,所以需要保证除根节点外的每一层不能有重复元素。

实现

class Solution {
	//记录解集
    List<List<Integer>> lists = new LinkedList<>();
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        if(candidates == null || candidates.length == 0 || target < 0) return lists;
		
		//排序
        Arrays.sort(candidates);
        //DFS
        dfs(candidates, 0, target, new LinkedList<Integer>());
        return lists;
    }

	//FDS
    public void dfs(int[] arr, int start, int target, LinkedList<Integer> list){
    	//目标值等于0,添加对应组合,递归结束
        if(target == 0){
            lists.add(new LinkedList<Integer>(list));
            return;
        }

        for(int i = start; i < arr.length; i ++){
        	//数组元素比目标值还大,退出循环
            if(arr[i] > target) break;
            
			//保证每一层元素不重复,去除重复组合
            if(i > start && arr[i] == arr[i - 1]) continue;
            
            list.addLast(arr[i]);
            //开始位置为i + 1,保证元素不重复使用
            dfs(arr, i + 1, target - arr[i], list);
            //回溯删除list中的元素
            list.removeLast();
        }
    }
}

你可能感兴趣的:(leetcode记录)