LeetCode偶爾一題 —— 39. Combination Sum(回溯算法系列)

題目描述

Given a set of candidate numbers (candidates) (without duplicates) and a target number (target), find all unique combinations in candidates where the candidate numbers sums to target. javascript

The same repeated number may be chosen from candidates unlimited number of times. 前端

Note:java

  • All numbers (including target) will be positive integers.
  • The solution set must not contain duplicate combinations.

大意:給定一組不含重複數字的數組和一個目標數字,在數組中找出全部數加起來等於給定的目標數字的組合。git

輸入

candidates = [2,3,6,7], target = 7

輸出

[
  [7],
  [2,2,3]
]

分析題目

因爲咱們須要找到多個組合,簡單的使用 for 循環確定是不行的,這時候咱們能夠使用回溯算法來解決這個問題。github

用回溯算法解決問題的通常步驟:算法

  1. 針對所給問題,定義問題的解空間,它至少包含問題的一個(最優)解。
  2. 肯定易於搜索的解空間結構,使得能用回溯法方便地搜索整個解空間 。
  3. 以深度優先的方式搜索解空間,而且在搜索過程當中用剪枝函數避免無效搜索。

根據題目的描述咱們知道它知足了咱們所說的步驟一,下面咱們來肯定搜索的思路👇數組

搜索的思路

回溯通常須要遍歷全部的狀況來找出問題的解,在寫代碼以前咱們不妨先畫出一個遞歸樹,理清咱們寫代碼的思路👇微信

因爲數組中的數字是能夠被重複使用的,因此對於同一個數字也要向下遞歸。可是,對於 [2,2,3][2,3,2] 這樣的結果 實際上是重複的,咱們須要剔除掉重複的項。
能夠這樣優化遞歸樹👇函數

其餘問題

如何保存數據

剛刷題目的時候看到這類多種解的問題常常會感到懵逼,其實這裏一般的解法是傳入一個臨時數組,進入遞歸前 push 一個結果,結束以前能夠用一個全局數組保存下來,結束以後在臨時數組pop 掉它。優化

如何肯定結束條件

結束條件一般題目中就會給出,通常來講找到給出的解或者遞歸層數達到上限就能夠結束遞歸

示例代碼

function foo (nums, target) {
    let result = []
    
    dfs(0, 0, [])
    return result
    
    function dfs (index, sum, tmp) {
        if (sum === target) {
            result.push(tmp.slice())
        }
        if (sum > target) {
            return
        }
        for (let i = index; i < nums.length; i++) {
            tmp.push(nums[i])
            dfs(i, sum + nums[i], tmp)
            tmp.pop()
        }
    }
}

總結

對於這類題目,使用回溯算法顯然很方便。固然,除了遞歸以外也能用 或者 隊列 來解決。另外,對於前端同窗,遇到須要開闢臨時數組的題目時,若是存在賦值操做,記得返回它的淺複製,如 result.push(tmp.slice()),不然會對結果產生影響。

原題地址: Combination Sum
代碼不定時更新,歡迎 star 個人 repo

掃描下方的二維碼或搜索「tony老師的前端補習班」關注個人微信公衆號,那麼就能夠第一時間收到個人最新文章。

相關文章
相關標籤/搜索