Leetcode39. 组合总和
题目描述
给定一个无重复元素的数组 candidates
和一个目标数 target
,找出 candidates
中所有可以使数字和为 target
的组合。
candidates
中的数字可以无限制重复被选取。
说明:
- 所有数字(包括
target
)都是正整数。
- 解集不能包含重复的组合。
示例 1:
1 2 3 4 5 6
| 输入:candidates = [2,3,6,7], target = 7, 所求解集为: [ [7], [2,2,3] ]
|
示例 2:
1 2 3 4 5 6 7
| 输入:candidates = [2,3,5], target = 8, 所求解集为: [ [2,2,2,2], [2,3,3], [3,5] ]
|
提示:
1 <= candidates.length <= 30
1 <= candidates[i] <= 200
candidate
中的每个元素都是独一无二的。
1 <= target <= 500
解题思路
这道题也是用DFS+回溯的方式暴力求解。难点在于如何重复选取元素。
暴力解法的写法有两种不同的实现。
一种方法是index
来标记现在处理元素的下标,每一个元素都有选取和不选取两种状态,分别对应两个进一步的递归。递归的出口在处理完所有的元素或者target
的值变为了0。在实现重复选取元素
这一点上,通过对index
的赋值来实现。在选取当前index
的元素后,递归处理下一个元素,如果是不重复选取元素就为index+1
,如果是重复选取元素就仍然为index
。由于index
之前的元素已经有选取、不选取、重复选取的操作了,继续递归下去就实现了整体的重复选取元素。
另一种方法是用循环来实现选取或者不选取。思路与第一种方法是大体一致的。要注意循环的指示i
初始值就不为0,而是index
,这样才不会重复。这种实现方法容易实现剪枝,当target<candidates[i]
直接结束循环就可以。
具体的实现细节可以参见示例代码:
示例代码
未剪枝的两个版本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| vector<vector<int>>ans;
void DFS(vector<int>& candidates,int target,vector<int>temp,int index) { if(target<0||index>=candidates.size()) { return; } if(target<candidates[index]) { index=candidates.size(); } if(target==0) { ans.push_back(temp); return; }
DFS(candidates,target,temp,index+1); temp.push_back(candidates[index]); DFS(candidates,target-candidates[index],temp,index);
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) { if(candidates.empty()) return {}; sort(candidates.begin(),candidates.end()); vector<int>temp; DFS(candidates,target,temp,0); return ans; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| vector<vector<int>>ans;
void DFS(vector<int>& candidates,int target,vector<int>&temp,int index) { if(target<0) return; if(target==0) { ans.push_back(temp); return; } for(int i=index;i<candidates.size();++i) { temp.push_back(candidates[i]); DFS(candidates,target-candidates[i],temp,i); temp.pop_back(); }
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) { if(candidates.empty()) return {}; vector<int>temp; DFS(candidates,target,temp,0); return ans; }
|
剪枝后的版本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| vector<vector<int>>ans;
void DFS(vector<int>& candidates,int target,vector<int>&temp,int index) { if(target==0) { ans.push_back(temp); return; } for(int i=index;i<candidates.size();++i) { if(target<candidates[i]) break; temp.push_back(candidates[i]); DFS(candidates,target-candidates[i],temp,i); temp.pop_back(); }
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) { if(candidates.empty()) return {}; sort(candidates.begin(),candidates.end()); vector<int>temp; DFS(candidates,target,temp,0); return ans; }
|