1. 程式人生 > 其它 >Combination Sum II 組合數求和之2-Leetcode

Combination Sum II 組合數求和之2-Leetcode

原題:

Given a collection of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.

Each number in C may only be used once in the combination.

Note:

  • All numbers (including target) will be positive integers.
  • Elements in a combination (a1, a
    2, … , ak) must be in non-descending order. (ie, a1 ≤ a2 ≤ … ≤ ak).
  • The solution set must not contain duplicate combinations.

For example, given candidate set 10,1,2,7,6,1,5 and target 8,  A solution set is:  [1, 7] [1, 2, 5] [2, 6] [1, 1, 6]


本題和Combination Sum 非常類似,也是從一組數中找到其和為指定值的所有組合。但是本題的特殊之處在於每個給出的候選數只能用一次,且組合不能重複。

思路:

  • 大體思路不變,仍是一個類似深搜的樹,只不過原本樹的每個節點下的子節點包括自身,而本題的樹的每一個節點的子節點是所有排在該節點之後的數,而不包括其本身。如【1,1,2,5,6,7,10】,第一個1的子節點是(1,2,5,6,7,10),第二個1的子節點是(2,5,6,7,10)。
  • 第二個難點在於組合不能重複。譬如僅使用第一個1的組合可以是(1,7),(1,2,5);而僅使用第二個1的組合也可以是(1,7),(1,2,5)。所以要加入一個判斷機制。每當迴圈走過一個節點,我們要判斷下一個節點是不是和上一個節點相同,相同的話就必須跳過。

程式碼如下:

public class Solution {
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        Arrays.sort(candidates);
        solve(candidates, 0, target, new LinkedList<Integer>());
        return ans;
    }
    private List<List<Integer>> ans=new LinkedList<>();
    private  void solve(int[] candidates,int start,int target,LinkedList<Integer> current){
        if (target==0){
            ans.add(copy(current));
            return;
        }
        if (start>=candidates.length){
            return;
        }
        if (target<candidates[start]){
            return;
        }
        else {
            for (int iterator=start;iterator<candidates.length;iterator++){
                if (candidates[iterator]>target){
                    break;
                }
                //如果該節點和上一個節點值相同,那麼它的所有組合必然包括在上一個節點的所有組合裡,必須跳過
                if (iterator>start&&candidates[iterator]==candidates[iterator-1]){
                    continue;
                }
                current.add(candidates[iterator]);
                solve(candidates, iterator+1, target - candidates[iterator], current); //每使用過iterator,就要+1,使得每個數只用一次
                current.pollLast();
            }
            return;
        }
    }
    private LinkedList<Integer> copy(LinkedList<Integer> source){
        LinkedList<Integer> dest=new LinkedList<>();
        for (int i:source){
            dest.add(i);
        }
        return dest;
    }
}