Python
法1:DFS+回溯_选或不选
class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
res = list()
tmp = list()
candidates.sort() # 剪枝优化
self.dfs(candidates, 0, target, tmp, res)
return res
def dfs(self, candidates, start, residual, tmp, res):
if residual == 0:
res.append(tmp.copy())
return
if start == len(candidates) or residual < candidates[start]: # 剪枝优化
return
# 不选择candidates[start]
self.dfs(candidates, start+1, residual, tmp, res)
# 选择candidates[start]
tmp.append(candidates[start])
self.dfs(candidates, start, residual-candidates[start], tmp, res)
tmp.pop()
旧解法
法1:回溯
必须掌握基本算法!!!
class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> res = new ArrayList<>();
List<Integer> tmp = new ArrayList<>();
dfs(candidates, 0, target, res, tmp);
return res;
}
public void dfs(int[] candidates, int idx, int target, List<List<Integer>> res, List<Integer> tmp) {
if (idx == candidates.length) {
return;
}
if (target == 0) {
res.add(new ArrayList<>(tmp));
return;
}
dfs(candidates, idx + 1, target, res, tmp); // 不选idx
if (target >= candidates[idx]) { // 选择idx
tmp.add(candidates[idx]);
dfs(candidates, idx, target - candidates[idx], res, tmp);
tmp.remove(tmp.size() - 1);
}
}
}
法2:回溯+剪枝
先排序,再dfs,可以进一步剪枝
参考链接
class Solution {
void backtrack(List<Integer> state, int target, int[] choices, int start, List<List<Integer>> res) {
// 子集和等于 target 时,记录解
if (target == 0) {
res.add(new ArrayList<>(state));
return;
}
// 遍历所有选择
// 剪枝二:从 start 开始遍历,避免生成重复子集
for (int i = start; i < choices.length; i++) {
// 剪枝一:若子集和超过 target ,则直接结束循环
// 这是因为数组已排序,后边元素更大,子集和一定超过 target
if (target - choices[i] < 0) {
break;
}
// 尝试:做出选择,更新 target, start
state.add(choices[i]);
// 进行下一轮选择
backtrack(state, target - choices[i], choices, i, res);
// 回退:撤销选择,恢复到之前的状态
state.remove(state.size() - 1);
}
}
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<Integer> state = new ArrayList<>(); // 状态(子集)
Arrays.sort(candidates); // 对 candidates 进行排序
int start = 0; // 遍历起始点
List<List<Integer>> res = new ArrayList<>(); // 结果列表(子集列表)
backtrack(state, target, candidates, start, res);
return res;
}
}