【Combination Sum I】
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 (a1, a2, … , ak) must be in non-descending order. (ie, a1 ≤ a2 ≤ … ≤ ak).
- 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]
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, a2, … , 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]
给定一个数组,从中找出一组数来,使其和等于target。数组无序,但都是正整数。
I和II不同的是,I数组里没有重复的数,但一个数可以用多次;II数组里有重复,一个数只能用一次。
I和II都要求返回结果中没有重复的解,且每个解中的数都按非递减排好序。
方法:回溯。先对数组进行排序,然后从小到大累加,等于或超过target时回溯。
【Combination Sum I】
public class Solution {
List<List<Integer>> ans = new ArrayList<List<Integer>>();
int[] cans = {};
public List<List<Integer>> combinationSum(int[] candidates, int target) {
this.cans = candidates;
Arrays.sort(cans);
backTracking(new ArrayList(), 0, target);
return ans;
}
public void backTracking(List<Integer> cur, int from, int target) {
if (target == 0) {
List<Integer> list = new ArrayList<Integer>(cur);
ans.add(list);
} else {
for (int i = from; i < cans.length && cans[i] <= target; i++) {
cur.add(cans[i]);
backTracking(cur, i, target - cans[i]);
cur.remove(new Integer(cans[i]));
}
}
}
}
注意第19行代码,当加入cans[i]后,下一次还是从i开始,因为一个数可以用多次。(与下面代码40行区别)
【Combination Sum II 】
public class Solution {
List<List<Integer>> ans = new ArrayList<List<Integer>>();
int[] num = {};
public List<List<Integer>> combinationSum2(int[] num, int target) {
this.num = num;
Arrays.sort(num);
backTracking(new ArrayList<Integer>(), 0, target);
return ans;
}
public void backTracking(List<Integer> cur, int from, int tar) {
if (tar == 0) {
//查看该解是否已经在结果集中,如对于输入[1,1]和1,只需放一个[1]到结果集中
boolean exist = false;
for (int i = ans.size() - 1; i >= 0 ; i--) {
List<Integer> tmp = ans.get(i);
if (tmp.size() != cur.size()) {
continue;
}
int j = 0;
while (j < cur.size() && tmp.get(j) == cur.get(j)) {
j++;
}
if (j == cur.size()) {
exist = true;
break;
}
}
//如果当前解不在结果集中,把其加入到结果集中
if (!exist) {
List<Integer> list = new ArrayList<Integer>(cur);
ans.add(list);
}
return;
}
for (int i = from; i < num.length && num[i] <= tar; i++) {
cur.add(num[i]);
backTracking(cur, i + 1, tar - num[i]);
cur.remove(new Integer(num[i]));
}
}
}
需要注意的是II的解法中,会出现相同的解,所以需要检查重复。(思考:I中为何不会出现重复解呢?)