Combination Sum 解答
阅读原文时间:2025年01月17日阅读:1

Question

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

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

Note:

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

For example, given candidate set 2,3,6,7 and target 7
A solution set is: 
[7] 
[2, 2, 3]

Solution 1 -- BFS

We can also draw the solution tree. For example, input is [2,3,6,7] and 22

                 []

         /     /    \    \

        [2]    [3]    [6]    [7]

      / /  \  \   / \ \    \ \    \

     [2] [3] [6][7]  [3][6][7]  [6][7]  [7]

    …………………………………………………….

We can find silimar regulation as Problem Subsets

Difference is here when we find that current sum of list is greater than target number, we will not add it to next array.

public class Solution {
public List> combinationSum(int[] candidates, int target) {
Arrays.sort(candidates);
List> result = new ArrayList>();
List> current = new ArrayList>();
Map map = new HashMap();
int length = candidates.length;
for (int i = 0; i < length; i++) { List list = new ArrayList();
list.add(candidates[i]);
if (target == candidates[i])
result.add(list);
if (target > candidates[i])
current.add(list);
map.put(candidates[i], i);
}

     while (current.size() > 0) {  
         List<List<Integer>> next = new ArrayList<List<Integer>>();  
         int l = current.size();  
         for (int i = 0; i < l; i++) {  
             List<Integer> tmp = current.get(i);  
             int ll = tmp.size();  
             int last = tmp.get(ll - 1);  
             int index = map.get(last);  
             // Sum up current list  
             int total = 0;  
             for (int j = 0; j < ll; j++)  
                 total += tmp.get(j);  
             for (int j = index; j < length; j++) {  
                 if (total + candidates\[j\] < target) {  
                     List<Integer> newList = new ArrayList<Integer>(tmp);  
                     newList.add(candidates\[j\]);  
                     next.add(newList);  
                 } else if (total + candidates\[j\] == target) {  
                     List<Integer> newList = new ArrayList<Integer>(tmp);  
                     newList.add(candidates\[j\]);  
                     result.add(newList);  
                 }  
             }  
         }  
         current = next;  
     }  
     return result;  
 }  

}

Solution 2 -- DFS

This also can be solved by DFS. End criterion is leftTarget <= 0.

Refer to this blog, we have two ways to check duplicated solutions.

1.       if(i>0 && candidates[i] == candidates[i-1])//deal with dupicate
                 continue;

2.       if(!res.contains(item)) 
                res.add(new ArrayList(item));

public class Solution {
public List> combinationSum(int[] candidates, int target) {
Arrays.sort(candidates);
List> result = new ArrayList>();
for (int i = 0; i < candidates.length; i++) { dfs(candidates, target, i, result, new ArrayList());
}
return result;
}

 private void dfs(int\[\] nums, int target, int start, List<List<Integer>> result, List<Integer> list) {  
     if (target < 0)  
         return;  
     if (target == 0) {  
         // Avoid duplicated solutions  
         if (!result.contains(list))  
             result.add(new ArrayList<Integer>(list));  
         return;  
     }  
     for (int i = start; i < nums.length; i++) {  
         list.add(nums\[i\]);  
         dfs(nums, target - nums\[i\], i, result, list);  
         list.remove(list.size() - 1);  
     }  
 }  

}