回溯 + 剪枝 無重複元素的數組 candidates 和一個目標數 target 數字可以無限制重複被選取

給定一個無重複元素的數組 candidates 和一個目標數 target ,找出 candidates 中所有可以使數字和爲 target 的組合。

candidates 中的數字可以無限制重複被選取。

說明:

  • 所有數字(包括 target)都是正整數。
  • 解集不能包含重複的組合。 

示例 1:

輸入: candidates = [2,3,6,7], target = 7,
所求解集爲:
[
  [7],
  [2,2,3]
]

示例 2:

輸入: candidates = [2,3,5], target = 8,
所求解集爲:
[
  [2,2,2,2],
  [2,3,3],
  [3,5]
]

 

去重複

在搜索的時候,需要設置搜索起點的下標 begin ,由於一個數可以使用多次,下一層的結點從這個搜索起點開始搜索;
在搜索起點 begin 之前的數因爲以前的分支搜索過了,所以一定會產生重複。


剪枝提速
如果一個數位搜索起點都不能搜索到結果,那麼比它還大的數肯定搜索不到結果,基於這個想法,我們可以對輸入數組進行排序,以減少搜索的分支;

排序是爲了提高搜索速度,非必要;

搜索問題一般複雜度較高,能剪枝就儘量需要剪枝。把候選數組排個序,遇到一個較大的數,如果以這個數爲起點都搜索不到結果,後面的數就更搜索不到結果了。

 

import java.util.ArrayDeque;

import java.util.ArrayList;

import java.util.Arrays;

import java.util.Deque;

import java.util.List;

 

class Solution {

    public static List<List<Integer>> combinationSum(int[] candidates, int target) {

        List<List<Integer>> list = new ArrayList<List<Integer>>();

        Arrays.sort(candidates);

        def(new ArrayDeque<>(), 0, 0, target, candidates, list);

        return list;

    }

 /**
     * @param candidates 數組輸入
     * @param now    當前值

     * @param target    目標值
     * @param begin      本輪搜索的起點下標
     * @param path       從根結點到任意結點的路徑
     * @param list        結果集變量
     */

    

    private static void def(Deque<Integer> path, int begin, int now ,int target, int[] candidates ,List<List<Integer>> list) {

        if(now == target) {

            list.add(new ArrayList<Integer>(path));

            return;

        }

        for (int i = begin ; i < candidates.length ; i++) {

            //剪枝

            if(now + candidates[i] > target) {

                break;

            }

            path.addLast(candidates[i]);

            def(path , i ,now + candidates[i] ,target ,candidates ,list);

            path.removeLast();

        }

    }

}

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