(LeetCode 39)組合總和 [DFS: 暴力搜尋 + 剪枝 + 去重]
39. 組合總和
給定一個無重複元素的陣列 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]
]
分析:
首先我們可以暴力枚舉出所有的正確組合。但是會存在"重複"問題。如[2,2,3], [3,2,2],[2,3,2]…
如何去重呢?
對於重複的問題,是因為在某一解中我們已經先添加了candidates[i] , 然後再加入candidates[j] (i < j) ; 而在另一個解中是按照:先新增candidates[j] 後 加入 candidates[i] 所造成的。
所以為了防止重複解出現,我們只需規定: 在某一個可行解中,它的所有元素是按照它們在candidates[]中的索引大小順序新增的,即:不能先新增後面的數,再新增前面的數。
我們使用 int used 來表示:當前組合cur[]中,已經使用到了第used個元素,所以之後為了不產生重複解,cur[]只能從candidates[used]開始新增。
dfs函式引數的含義:
cur : 當前試探的組合
sum: 當前組合的和
used: 當前組合cur[]中,已經使用到了第used個元素
…
優化:剪枝
先將candidates[]排序,若新增某個數後sum > target ,由於後面的數更大,一定也會使得 sum > target, 所以不用考慮,可以直接剪枝掉。
AC程式碼:
class Solution { public: int n; void dfs(vector<int> cur, int sum, int used, vector<vector<int>>& ans,vector<int>& candidates,int target) { if(sum > target) return; if(sum == target) { ans.push_back(cur); return; } for(int i=used;i<n;i++) { vector<int> t = cur; t.push_back(candidates[i]); dfs(t,sum+candidates[i],i,ans,candidates,target); if(sum+candidates[i] > target) break; } } vector<vector<int>> combinationSum(vector<int>& candidates, int target) { sort(candidates.begin(),candidates.end()); vector<vector<int>> ans; vector<int> cur; n = candidates.size(); dfs(cur,0,0,ans,candidates,target); return ans; } };