題目描述
Given a set of candidate numbers (
candidates
) (without duplicates) and a target number (target
), find all unique combinations incandidates
where the candidate numbers sums totarget
.The same repeated number may be chosen from candidates unlimited number of times.
Note:
- All numbers (including target) will be positive integers.
- The solution set must not contain duplicate combinations.
大意:給定一組不含重複數字的數組和一個目標數字,在數組中找出所有數加起來等於給定的目標數字的組合。
輸入
candidates = [2,3,6,7], target = 7
輸出
[
[7],
[2,2,3]
]
分析題目
由於我們需要找到多個組合,簡單的使用 for
循環肯定是不行的,這時候我們可以使用回溯算法來解決這個問題。
用回溯算法解決問題的一般步驟:
- 針對所給問題,定義問題的解空間,它至少包含問題的一個(最優)解。
- 確定易於搜索的解空間結構,使得能用回溯法方便地搜索整個解空間 。
- 以深度優先的方式搜索解空間,並且在搜索過程中用剪枝函數避免無效搜索。
根據題目的描述我們知道它滿足了我們所說的步驟一,下面我們來確定搜索的思路👇
搜索的思路
回溯一般需要遍歷所有的情況來找出問題的解,在寫代碼之前我們不妨先畫出一個遞歸樹,理清我們寫代碼的思路👇
由於數組中的數字是可以被重複使用的,所以對於同一個數字也要向下遞歸。但是,對於 [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老師的前端補習班」關注我的微信公衆號,那麼就可以第一時間收到我的最新文章。