OJ 组合总和
题目:
给你一个 无重复元素 的整数数组
candidates
和一个目标整数target
,找出candidates
中可以使数字和为目标数target
的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。
candidates
中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。对于给定的输入,保证和为
target
的不同组合数少于150
个。
示例:
代码编程:
class Solution {
public:
vector<vector<int>> ans;
vector<int> path;
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
dfs(candidates, 0, target);
return ans;
}
void dfs(vector<int>& cs, int deep, int target) {
if (target == 0) {
ans.push_back(path); // 搜到一种答案
return;
}
if (deep == cs.size()) {
// 深度等于可选数组 则该dfs组合不对 必须在if(target ==
// 0)前面,不然可能导致最后一个元素 == target的时候选不上
return;
}
for (int i = 0; i * cs[deep] <= target; i++) {
// 按照从左向右每个数字的个数枚举
//这是一个循环,用于尝试当前深度的数字cs[deep]的不同倍数,
//直到这个数字的倍数超过目标值target。
dfs(cs, deep + 1, target - cs[deep] * i);
//递归调用dfs函数,尝试在当前路径上添加cs[deep]的i倍,
//并更新目标值为target - cs[deep] * i。
path.push_back(cs[deep]);//将当前数字cs[deep]添加到路径path中。
}
for (int i = 0; i * cs[deep] <= target; i++) {
//这个循环与上面的循环相同,用于回溯,移除之前添加到路径中的数字。
// 回溯
path.pop_back();//从路径path中移除最后一个元素,实现回溯。
}
}
};
代码分析:
dfs(candidates , 0 , target);
调用dfs
函数开始深度优先搜索。
return ans;
返回存储所有组合的二维向量。
void dfs(vector<int> &cs , int deep , int target){
定义了一个名为dfs
的成员函数,用于执行深度优先搜索。它接受当前的候选数组cs
、当前搜索的深度deep
和当前的目标值target
作为参数。
if(target == 0){
如果当前的目标值target
为0,说明找到了一个有效的组合。
ans.push_back(path);
将当前路径path
添加到答案数组ans
中。
return;
返回,结束当前的递归调用。
if(deep == cs.size()){
如果当前搜索的深度等于候选数组的大小,说明已经考虑了所有候选数字,但还没有达到目标值,因此这是一个无效的路径。
return;
返回,结束当前的递归调用。
for(int i = 0; i * cs[deep] <= target; i++){
这是一个循环,用于尝试当前深度的数字cs[deep]
的不同倍数,直到这个数字的倍数超过目标值target
。
dfs(cs , deep + 1 , target - cs[deep] * i);
递归调用dfs
函数,尝试在当前路径上添加cs[deep]
的i
倍,并更新目标值为target - cs[deep] * i
。
path.push_back(cs[deep]);
将当前数字cs[deep]
添加到路径path
中。
for(int i = 0; i * cs[deep] <= target; i++){
这个循环与上面的循环相同,用于回溯,移除之前添加到路径中的数字。
path.pop_back();
从路径path
中移除最后一个元素,实现回溯。这段代码中的两个
for
循环是对称的,第一个循环用于尝试添加当前数字的不同倍数到路径中,第二个循环用于回溯,移除之前添加的数字,以便尝试其他可能的组合。这种回溯策略是解决组合问题常用的方法。
代码示意图分析:以示例一为例
题目来源:39. 组合总和 - 力扣(LeetCode)