题目:
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.
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]
]
大意:
给定一个数组,从中找出一组数来,使其和等于target。
有一个正整数集合C,和一个目标数T(T也为正整数)。现从C中选出一些数,使其累加和恰好等于T(C中的每个数都可以取若干次),求所有不同的取数方案。
思路:
数组无序,但都是正整数,所以我们要先将其排好序。
数组里没有重复的数,但一个数可以用多次。
返回结果中没有重复的解,且每个解中的数都按非递减排好序。
这道题使用DFS,递归是解决DFS的常用方法。
PS:
深度优先搜索(DFS)是搜索算法的一种。最早接触DFS应该是在二叉树的遍历里面,二叉树的先序、中序和后序遍历实际上都属于深度优先遍历,实质就是深度优先搜索,后来在图的深度优先遍历中则看到了更纯正的深度优先搜索算法。
通常,我们将回溯法和DFS等同看待,可以用一个等式表示它们的关系:回溯法=DFS+剪枝。所以回溯法是DFS的延伸,其目的在于通过剪枝使得在深度优先搜索过程中如果满足了回溯条件不必找到叶子节点,就截断这一条路径,从而加速DFS。实际上,即使没有剪枝,DFS在从下层回退到上层的时候也是一个回溯的过程,通常这个时候某些变量的状态。DFS通常用递归的形式实现比较直观,也可以用非递归,但通常需要借组辅助的数据结构(比如栈)来存储搜索路径。
代码:
public class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> result = new ArrayList<List<Integer>>();
if(candidates == null || candidates.length == 0) {
return result;
}
//排序
Arrays.sort(candidates);
List<Integer> current = new ArrayList<Integer>();
combinationSum(candidates, target, 0, current, result);
return result;
}
private void combinationSum(int[] candidates, int target, int j, List<Integer> curr, List<List<Integer>> result) {
if(target == 0) {
List<Integer> temp = new ArrayList<Integer>(curr);
result.add(temp);
return;
}
for(int i = j; i < candidates.length; i++) {
if(target < candidates[i]) {
return;
}
curr.add(candidates[i]);
combinationSum(candidates, target - candidates[i], i, curr, result);
curr.remove(curr.size() - 1);//回溯,去除新加入的元素,回到上一层的状态
}
}
}