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]);

        }

    }




}




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