一、回溯法簡介
回溯法(探索與回溯法)是一種選優搜索法,又稱爲試探法,按選優條件向前搜索,以達到目標。但當探索到某一步時,發現原先選擇並不優或達不到目標,就退回一步重新選擇,這種走不通就退回再走的技術爲回溯法,而滿足回溯條件的某個狀態的點稱爲“回溯點”。回溯法很有趣可以解決一系列的問題,比如子集問題、排列問題以及八皇后問題等。是個很值得研究和學習的算法。可以細看我之前的博客https://blog.csdn.net/kupepoem/article/details/106529463
二、題目
(來源:https://leetcode-cn.com/problems/combination-sum)
給定一個無重複元素的數組 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]
]
三、實戰
1、思路
求所有的解是回溯法的強項,暴力進行回溯也是可以求解的只是時間效率肯定是比較低的,那麼如何剪枝呢
a、定義一個resval resval爲殘差值 這樣我們可以在resval==0時記錄結果並剪枝,resval<0時候剪枝
b、排序 這樣我們可以一直往前找
2、實現
void combinationSum_help(vector<int>& candidates,int start, vector<int> &resdfs, vector<vector<int>> &res,int resval)
{
if (resval == 0)
{
res.push_back(resdfs);
return;//剪枝
}
else if(resval<0)
{
return;//剪枝
}
for (int i = start; i < candidates.size(); ++i)
{
resdfs.push_back(candidates[i]);
combinationSum_help(candidates, i, resdfs, res, resval - candidates[i]);
resdfs.pop_back();
}
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
vector<vector<int>> res;
vector<int> resdfs;
std::sort(candidates.begin(), candidates.end(), [](int a, int b) {
return a < b;
});
combinationSum_help(candidates, 0, resdfs, res, target);
return res;
}