主要使用方法是backtracking。
Combination Sum
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]
解答:为了减少许多不必要的循环过程,应该先把candidates排序,这样当目前遍历到的元素和已经大于target时,就可以不必再访问candidates后面的元素,直接退回到上个选择处进行选择。
另外,由于candidates集合中的每个数都可以使用无数次,故每次递归调用都应该从上次加入的元素开始遍历。
public class Solution { public List<List<Integer>> combinationSum(int[] candidates, int target) { List<List<Integer>> result = new LinkedList<List<Integer>>(); if (candidates == null || candidates.length == 0) { return result; } Arrays.sort(candidates); List<Integer> temp = new LinkedList<Integer>(); helper(candidates, target, result, temp, 0); return result; } public void helper (int[] candidates, int target, List<List<Integer>> result, List<Integer> temp, int index) { if (target == 0) { result.add(new LinkedList<Integer>(temp)); return; } for (int i = index; i < candidates.length && candidates[i] <= target; i++) { temp.add(candidates[i]); helper(candidates, target - candidates[i], result, temp, i); //从上次加入的元素开始遍历 temp.remove(temp.size() - 1); } } }
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]
解答:与上题一样应该先把candidates排序。
这题需要注意的有两点是:
1. 每个元素只能用一次,所以每次递归都应该从当前加入元素的下一个元素开始遍历;
2. 集合中含有重复元素,所以在每次for循环在candidates挑选元素时,应将已经挑选过的元素过滤(因为加入此元素的结果已经加入结果集合),避免集合中结果出现重复。递归中则不用考虑起始点与上个元素是否相同,因为递归是在前面元素确定的情况下加入下一元素,它们在同一结果中。
public class Solution { public List<List<Integer>> combinationSum2(int[] candidates, int target) { Arrays.sort(candidates); List<List<Integer>> rst = new ArrayList<List<Integer>>(); List<Integer> temp = new ArrayList<Integer>(); helper(rst, temp, candidates, target, 0); return rst; } public void helper(List<List<Integer>> rst, List<Integer> temp, int[] candidates, int target, int index) { if (target == 0) { rst.add(new ArrayList<Integer>(temp)); return; } for (int i = index; i < candidates.length && candidates[i] <= target; i++) { if (i > index && candidates[i] == candidates[i - 1]) { continue; } temp.add(candidates[i]); helper(rst, temp, candidates, target - candidates[i], i + 1); //从下一个元素开始遍历 temp.remove(temp.size() - 1); } } }
Combination Sum III
Find all possible combinations of k numbers that add up to a number n, given that only numbers from 1 to 9 can be used and each combination should be a unique set of numbers.
Ensure that numbers within the set are sorted in ascending order.
Example 1:
Input: k = 3, n = 7
Output:
[[1,2,4]]
Example 2:
Input: k = 3, n = 9
Output:
[[1,2,6], [1,3,5], [2,3,4]]
解答:可以看做是上题的一种特殊情况, candidates数组中的元素为1到9,且不含重复元素,上题中去重的判断可以去掉。
public class Solution { public List<List<Integer>> combinationSum3(int k, int n) { List<List<Integer>> rst = new ArrayList<List<Integer>>(); List<Integer> temp = new ArrayList<Integer>(); helper(rst, temp, k, n, 1); return rst; } public void helper(List<List<Integer>> rst, List<Integer> temp, int k, int n, int number) { if (k == temp.size() && n == 0) { rst.add(new ArrayList<Integer>(temp)); return; } for (int i = number; i <= 9 && i <= n; i++) { temp.add(i); helper(rst, temp, k, n - i, i + 1); temp.remove(temp.size() - 1); } } }
总结:本题需要注意的是每次递归里面的循环起始点,以及如何避免结果集的重复。