1. 程式人生 > >39. Combination Sum 40 Combination Sum 2(Array, DFS)

39. Combination Sum 40 Combination Sum 2(Array, DFS)

39. Combination Sum

Given a set of candidate numbers (candidates) (without duplicates) and a target number (target), find all unique combinations in candidates where the candidate numbers sums to target.

The same repeated number may be chosen from candidates unlimited number of times.

Note:

  • All numbers (including target) will be positive integers.
  • The solution set must not contain duplicate combinations.

Example 1:

Input: candidates = [2,3,6,7], target = 7
A solution set is:
[
  [7],
  [2,2,3]
]

思路:依舊使用DFS,因為每個元素可以重複使用多次,所以呼叫的時候從當前位置開始。用target儲存當前值,如果小於零就去掉最後一個元素並回溯,如果等於零就加入res,如果大於零就繼續遞迴。一開始我將迴圈每次都從0開始,就會出現【2,2,3】,【2,3,2】,【3,2,2】的結果。因此首先對陣列排序,然後向前搜尋不重複。

 public List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<List<Integer>> res = new ArrayList<>();
        if(candidates==null ||candidates.length==0)
            return res;
        List<Integer> tmp = new ArrayList<Integer>();
        Arrays.sort(candidates);
        doCombine(candidates, target,0, tmp, res);
        return res;
    }
    
    private void doCombine(int[] nums, int target, int pos,List<Integer> tmp, List<List<Integer>> res){
        for(int i=pos;i<nums.length;i++){
            target = target - nums[i];
            tmp.add(nums[i]);
            if(target<=0){
                if(target==0)
                    res.add(new ArrayList<Integer>(tmp));
                tmp.remove(tmp.size()-1);
                target = target + nums[i];
                return;
            }          
            doCombine(nums,target,i,tmp,res);
            tmp.remove(tmp.size()-1);
            target = target + nums[i];
        }
    }

40. Combination Sum 2

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

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

Note:

  • All numbers (including target) will be positive integers.
  • The solution set must not contain duplicate combinations.

Example 1:

Input: candidates = [10,1,2,7,6,1,5], target = 8,
A solution set is:
[
  [1, 7],
  [1, 2, 5],
  [2, 6],
  [1, 1, 6]
]

思路:

區別在於每個元素只能用一次。所以遞迴是應該是i+1.

為了避免重複,首先對陣列排序,然後連續兩個相同元素會產生相同結果,所以獎後一個元素跳過,這裡的方法和permutation2中用到的一樣。

public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        List<List<Integer>> res = new ArrayList<>();
        if(candidates==null ||candidates.length==0)
            return res;
        List<Integer> tmp = new ArrayList<Integer>();
        Arrays.sort(candidates);
        doCombine(candidates, target,0, tmp, res);
        return res;
    }
    private void doCombine(int[] nums, int target, int pos,List<Integer> tmp, List<List<Integer>> res){
        for(int i=pos;i<nums.length;i++){
            target = target - nums[i];
            tmp.add(nums[i]);
            if(target<=0){
                if(target==0)
                    res.add(new ArrayList<Integer>(tmp));
                tmp.remove(tmp.size()-1);
                target = target + nums[i];
                return;
            }                      
            doCombine(nums,target,i+1,tmp,res);//注意是i+1
            tmp.remove(tmp.size()-1);
            target = target + nums[i];
            while(i<nums.length-1 && nums[i]==nums[i+1])
                i++;//跳過相同結果
        }
    }