39. 组合总和
给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的数字可以无限制重复被选取。
说明:
所有数字(包括 target)都是正整数。
解集不能包含重复的组合。
示例 1:
输入:candidates = [2,3,6,7], target = 7,
所求解集为:
[
[7],
[2,2,3]
]
示例 2:
输入:candidates = [2,3,5], target = 8,
所求解集为:
[
[2,2,2,2],
[2,3,3],
[3,5]
]
回溯算法:一条路走到底,如果得到的结果不对则返回到上一步,选择另外几个方向走到底,遇到对的结果或确定接下来的路都错误或者本步所有的路都走完,返回到上一步进行循环。
class Solution39:
def combinationSum(self, candidates: list(), target: int):
def dfs(candidates, begin, size, path, res, target):
if target < 0:
return
if target == 0:
res.append(path)
return
for index in range(begin, size):
dfs(candidates, index, size, path + [candidates[index]], res, target - candidates[index])
size = len(candidates)
if size == 0:
return []
path = []
res = []
dfs(candidates, 0, size, path, res, target)
return res
class Solution {
public: // 2 3 6 7 7
vector<vector<int>> combinationSum(vector<int>& candidates, int target)
{
int size = candidates.size();
vector<vector<int>>res;
vector<int>path;
sort(candidates.begin(),candidates.end());
Calu(candidates,target,0,size,res,path);
return res;
}
void Calu(vector<int>&cand,int target,int begin,int size,vector<vector<int>>&res,vector<int>&path)
{
if(target <0)
{
return;
}
if(target == 0)
{
res.push_back(path);
cout<<"res = ";
for(int i = 0;i<res.size();i++)
{
for(int j = 0;j<res[i].size();j++)
cout<<res[i][j];
}
cout<<endl;
return;
}
for(int index =begin;index<size;index++)
{
path.push_back(cand[index]);
cout<<"path = ";
for(int i = 0;i<path.size();i++)
{
cout<<path[i];
}
cout<<endl;
//Calu执行完,就表示有target<=0 总是需要剔除最后一个元素。
Calu(cand,target - cand[index],index,size,res,path);
path.pop_back(); //这句语句执行时,说明上一句Calu已经执行完了 ,当target<=0时才会执行完 所以需要把最后一个元素剔除,准备放入下一个元素
if(target - cand[index] <=0) //出现最新target<=0时,本层循环终止
{
break; //当出现最新target小于0时,本次循环终止,直接进入上一层循环。
}
}
}
};
回溯算法的核心:
path.push_back(cand[index]); //插入
Calu(cand,target - cand[index],index,size,res,path); //判断是否继续插入,内部实现正确保存,错误返回。
path.pop_back(); //撤销
每条路径都尝试并且都将路径保存,符合返回上一路经的条件时,返回到上一路径。