LeetCode39. 組合總和
題目敘述:
給定一個無重複元素的陣列 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] ]
思路:
- 題目中提到同一個數字可以無限制的被選取,那麼我們就想,如果這個陣列中有0怎麼辦?那不是無窮選了?但是我們看到題目中說,所有數字都是正整數,所以我們放心了,我們可以先畫出遞迴搜尋樹來形象的觀察我們這題的操作過程
- 注:本圖應用了程式碼隨想錄的原圖,想要了解更加深刻的讀者可以去看看原作者的文章:
- [程式碼隨想錄 (programmercarl.com)]()
1.回溯函式的引數以及返回值
- 我們需要一個一維陣列path存放當前路徑上的所有元素,並且需要一個二維陣列result存放所有的結果。
- 需要傳入一個目標值targetSum,這就是我們的目標和
- 並且我們需要一個sum來記錄當前路徑所有元素的總和,其實這個也不是必須的,我們可以透過加減targetSum來實現。不過這裡我們介紹使用sum的方法,這樣更加直觀!
2.遞迴的中止條件
- 注意圖中葉子節點的返回條件,因為本題沒有組合數量要求,僅僅是總和的限制,所以遞迴沒有層數的限制,只要選取的元素總和超過target,就返回!
//當sum≥targetSum就可以返回了
if(sum>=targetSum){
if(sum==targetSum) result.push_back(path);
return;
}
3. 單層遞迴的邏輯
-
我們透過for迴圈來控制橫向遍歷,透過控制遞迴函式來實現縱向遍歷,不過這裡的縱向遍歷可就不是i+1了,而是i,這裡一定要想清楚,因為這道題說一個元素是可以重複選取的!!!所以說縱向遍歷的時候,是可以包括當前遍歷的元素的,在程式碼體現上也就是遞迴函式的引數startindex==i,而不是i+1。
-
明白了這個之後,我們不難寫出程式碼:
for(int i=startindex;i<candidates.size();i++){
sum+=candidates[i];
path.push_back(candidates[i]);
//這裡是i,並不是i+1,因為同一個元素可以重複取
backtracking(candidates,targetSum,sum,i);
sum-=candidates[i];
path.pop_back();
}
- 在這裡我們也可以隱藏回溯的過程,程式碼更簡潔,但是初學者不推薦這種寫法
for(int i=startindex;i<candidates.size();i++){
path.push_back(candidates[i]);
//將回溯過程隱藏在遞迴函式當中
backtracking(candidates,targetSum,sum+candidates[i],i);
path.pop_back();
}
程式碼:
- 透過上面的分析,我們不難得出程式碼:
class Solution {
public:
vector<int> path;
vector<vector<int> > result;
void backtracking(vector<int> candidates,int targetSum,int sum,int startindex){
if(sum>=targetSum){
if(sum==targetSum) result.push_back(path);
return;
}
for(int i=startindex;i<candidates.size();i++){
//使用sum加減更直觀,也可以隱藏到回溯函式當中。
sum+=candidates[i];
path.push_back(candidates[i]);
//這裡是i,並不是i+1,因為同一個元素可以重複取
backtracking(candidates,targetSum,sum,i);
sum-=candidates[i];
path.pop_back();
}
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
path.clear();result.clear();
if(candidates.size()==0) return result;
backtracking(candidates,target,0,0);
return result;
}
};