LeetCode39. 組合總和

Tomorrowland_D發表於2024-08-14

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怎麼辦?那不是無窮選了?但是我們看到題目中說,所有數字都是正整數,所以我們放心了,我們可以先畫出遞迴搜尋樹來形象的觀察我們這題的操作過程

39.組合總和

  • 注:本圖應用了程式碼隨想錄的原圖,想要了解更加深刻的讀者可以去看看原作者的文章:
  • [程式碼隨想錄 (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;
    }
};

相關文章