【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]
【Combination Sum II 】
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中为何不会出现重复解呢?)