目錄
- 1、題目
- 2、思考分析
- 3、未經優化代碼
- 4、剪枝優化
1、題目
給定一個無重復元素的數組 candidates 和一個目標數 target ,找出 candidates 中所有可以使數字和為 target 的組合。
candidates 中的數字可以無限制重復被選取。
2、思考分析
解空間樹寬度部分即數組 candidates內集合,深度取決于target.
一開始的重復元素理解錯誤了,每層循環都從0開始:
for(int i=0;i<=candidates.size();i++)
這樣是不對的,會產生重復組合。
我們仍然需要采用startindex作為for起始位置,不過對于下一層我們的startindex不是startindex+1,而是仍然是startindex,這樣才能重復取相同元素。
![]() | ![]() |
3、未經優化代碼
class Solution {
public:vector<vector<int>> result;vector<int> res;int sum;void clear_solution_param(){result.clear();res.clear();sum=0;}void backtracking(vector<int>& candidates,int startindex,int n){ if(sum > n) return;if(sum == n){result.push_back(res);return;}for(int i=startindex;i<candidates.size();i++){//處理結點;res.push_back(candidates[i]);sum+=candidates[i];//遞歸,探索下一層backtracking(candidates,i,n); //遞歸sum-=candidates[i];//回溯,撤銷處理結果res.pop_back();}}vector<vector<int>> combinationSum(vector<int>& candidates, int target) {clear_solution_param();backtracking(candidates,0,target);return result;}
};
4、剪枝優化
先對數組進行排序,這樣集合元素排列就是有序的了,方便剪枝。(這個在回溯法中經常用到)
對于同一層的for循環,如果sum加上此時的候選元素的和大于target則沒有必要繼續深入下去了。
class Solution {
public:vector<vector<int>> result;vector<int> res;int sum;void clear_solution_param(){result.clear();res.clear();sum=0;}void backtracking(vector<int>& candidates,int startindex,int n){ if(sum > n) return;if(sum == n){result.push_back(res);return;}for(int i=startindex;i<candidates.size();i++){//由于輸入的數組是有序的,所以直接進行剪枝。如果sum加上這個集合元素大于目標,此層就不需要往后看了,因為后面的元素加上sum肯定大于目標if(sum+candidates[i]>n) break;//處理結點;res.push_back(candidates[i]);sum+=candidates[i];//遞歸,探索下一層backtracking(candidates,i,n); //遞歸sum-=candidates[i];//回溯,撤銷處理結果res.pop_back();}}vector<vector<int>> combinationSum(vector<int>& candidates, int target) {clear_solution_param();//排序加速剪枝sort(candidates.begin(),candidates.end());backtracking(candidates,0,target);return result;}
};