LeetCode40 组合总和(组合中含有重复元素)

组合总和>>>

在这里插入图片描述

这道题,采用递归+回溯,关键是需要进行剪枝解集中不能包含重复组合,怎么剪枝呢,画出隐形回溯树可以发现,若同一层的递归数据相等则除了相同数据第一次出现外,其他则跳过这条路径(必须基于数组是排序的);continu为小剪枝,break为大剪枝

在这里插入图片描述

package BDyNamicProgramming;

import sun.reflect.generics.tree.Tree;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @Author Zhou  jian
 * @Date 2020 ${month}  2020/4/26 0026  13:29
 */
public class Problem40 {

    /**
     *
     * @param candidates
     * @param target
     * @return
     * 这道题与上一问的区别在于:
     *
     *     第39题:candidates中的数字可以无限制重复被选取
     *      第40题:candidates中的每个数字在每个组合中只能使用一次
     *
     *  编码的不同之处在于下一层递归的起始索引不一样:
     *        第39题:还从候选数组的当前索引值开始
     *        第40题:从候选数组的当前索引值的下一位开始
     */
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {

        List<List<Integer>> rs = new ArrayList<>();
        List<Integer> path = new ArrayList<>();

        //对数组进行排序:排序视为了提前终止搜索,进行剪枝
        Arrays.sort(candidates);
        //标注:数组中哪些元素被使用到了:方便去重
//        boolean[] used = new boolean[candidates.length];

        dfs(candidates,target,path,rs,0);
        return rs;

    }


    public void dfs(int[] candidates,int target,List<Integer> path,List<List<Integer>> rs,int start){

        //符合值相等
        if(target==0){
            //由于r全局只适用到一份,到叶子节点的时候需要左一份拷贝
            rs.add(new ArrayList<>(path));
        }

        if(target<0) return;

        //递归加回溯
        //在当前的选择下,从start开始进行选择.start(包含)之后的位置都可以进行选择
        for(int i=start;i<candidates.length;i++){

            //数组中包含重复的元素必须进行去重
            //剪枝检测到重复分支的条件:

            //1、不是这层的第一个分支
            //2、当前选出的数和前一个分支相等

            //这个避免重复思想比较重要
            //这个方法最重要的作用是,可以让同一层级,不出现相同的元素
            //不同级的元素可以出现重复的元素
            //continue
            if(i>start&&candidates[i]==candidates[i-1]) continue;

            //大减职业,因为数组已经进行排序了,当前数据大于target则之后的数必然也大于
            //直接跳出剪枝即可
            if(candidates[i]>target) break;

            path.add(candidates[i]);

            //下轮搜索的起点为i+1,因为元素不可以重复使用,这里递归传递下去的是i+1而不是i
            dfs(candidates,target-candidates[i],path,rs,i+1);


            //进行回溯
            path.remove((Object)candidates[i]);

        }

    }




}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章