leetcode39 组合数和
题目:给定一个的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。candidates 中的数字可以无限制重复被选取
说明:所有数字(包括 target)都是正整数。解集不能包含重复的组合。
无重复元素(所以这个题没有在for里判断nums[i]==nums[i-1],因为每取一个i都生成一个分支,两个数相等,两个分支相等,得到结果重复,下面那个就要考虑了)
回溯的问题,每个循环取一次i,代表生成一个以nums[i] 为根节点的子树,那么去重复的话,就要看前后生成两个子树想不相等(根节点相不相等)
Java: 回溯
public List<List<Integer>> combinationSum(int[] nums, int target) {
List<List<Integer>> ans = new ArrayList<List<Integer>>();
//先排序 类似于三数之和的处理,
// 1.防止重复(相邻相等) 2.减枝 当前sum>0 说明后面也都不满足
Arrays.sort(nums);
backTrack(ans, new LinkedList<>(), nums, target, 0, 0);
return ans;
}
void backTrack(List<List<Integer>> ans, LinkedList<Integer> path, int[] nums,
int target, int sum, int start) {
if (sum == target) { // 要先判断 在下面的if之前判断
ans.add(new ArrayList<Integer>(path));
return;
}
if (sum > target || start == nums.length) // 非法递归出口
return;
for (int i = start; i < nums.length; ++i) {
if (i != 0 && nums[i] == nums[i - 1])
continue; // 防止重复
path.add(nums[i]);
backTrack(ans, path, nums, target, sum + nums[i], i);
path.removeLast(); // 回溯
}
}
C++:
vector<vector<int> > combinationSum(vector<int>& nums, int target) {
vector<vector<int> > ans;
sort(nums.begin(), nums.end());
vector<int> path;
DFS(ans, nums, path, true, target, 0);
return ans;
}
void DFS(vector<vector<int> > &ans, vector<int>& nums,vector<int>& path,
bool flag, int target, int index) {
if (target < 0) {
flag = false;
return;
}
if (target == 0) {
flag = false;
ans.push_back(path);
return;
}
for (int i = index; i < nums.size(); ++i) {
path.push_back(nums[i]);
DFS(ans, nums, path, flag, target - nums[i], i);
path.pop_back();
// 这里如果剪枝的话,nums必须要先排序,这样才能证明i后面的都没有用
if (!flag) break;
}
flag = true; // 不加的话,会比加了变慢??
}