题目链接:https://leetcode.com/problems/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]
解题思路:
以 [7, 3, 2] 18 为例说明思路
- 先把已知数组按从小到大的顺序排好。[2, 3, 7]
- 从最大的元素 7 开始,依次向较小元素的遍历
- 首先,判断 target(18) 能容纳多少个当前元素(7),18 / 7 = 2,18 最多能容纳 2 个 7,表明包含当前元素 7 的列表有两个,分别为包含一个 7 的列表[7, …] 和两个 7 的列表[7, 7, …]
- 然后,分别对两个列表进行递归。此时,对于第一个列表 target 变为 18 - 7 = 11,第二个列表 target 为 18 - 14 = 4。递归时,起始元素为比当前元素(7)小的元素,由于我们已经对原数组进行了排序,所以把当前元素 7 前面的元素 3 和 2 分别作为起始元素进行递归。也就是包含了两种情况,第一种,起始元素为3 [7, 3, …],第二种,[7, 7, 2, …]起始元素为 2,没有经过 3
- 以此类推,直到 target 为 0(找到所有元素),或者 target 小于数组中最小的元素(找不到符合要求的元素),递归结束。
简单来说
- 对原数组进行排序。
- 从最大的元素开始,根据目标数所能包含的元素个数,用目标数减去相应的元素的值。
例如,目标数能包含3个元素,则用目标数分别减去1个元素,两个元素,和三个元素。 - 剩下的值为下一轮递归的目标数,且下一轮递归从当前轮的元素的前面元素开始(分别以比当前元素小的元素作为起始元素)。
public class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> list = new ArrayList();
if(candidates == null || candidates.length == 0)
return list;
Arrays.sort(candidates);
for(int i = candidates.length - 1; i >= 0; i --) {
if(candidates[i] > target)
continue;
List<List<Integer>> subList = help(candidates, target, i);
for(List<Integer> l : subList) {
if(l != null && !list.contains(l))
list.add(l);
}
}
return list;
}
public List<List<Integer>> help(int[] candidates, int target, int k) {// k为元素下标
int n = target / candidates[k];
if(n < 1)
return null;
else { // n >= 1
List<List<Integer>> res = new ArrayList();
for(int i = 1; i <= n; i ++) {
List<Integer> list = new ArrayList();
for(int j = 0; j < i; j ++)
list.add(candidates[k]);
int find = target - i * candidates[k];
if(find == 0)
res.add(list);
else { // find > 0
if(k > 0) {
for(int t = 1; t <= k; t ++) {
List<List<Integer>> subList = help(candidates, find, k - t);
if(subList != null) {
for(List<Integer> l : subList) {
List<Integer> temp = new ArrayList(list);
temp.addAll(l);
Collections.sort(temp);
res.add(temp);
}
}
}
}
}
}
return res;
}
}
}
168 / 168 test cases passed.
Status: Accepted
Runtime: 316 ms
值得借鉴的另一种方法:http://46aae4d1e2371e4aa769798941cef698.devproxy.yunshipei.com/linhuanmars/article/details/20828631