题目重述
给定一个无重复元素的正整数数组 candidates 和一个正整数 target,需要找出 candidates 中所有可以使数字和为目标数 target 的唯一组合。candidates 中的数字可以无限制重复被选取。如果至少一个所选数字数量不同,则两种组合是不同的。
对于给定的输入,保证和为 target 的唯一组合数少于 150 个。
示例
示例 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]]
示例 3:
- 输入:
candidates = [2],target = 1 - 输出:
[]
示例 4:
- 输入:
candidates = [1],target = 1 - 输出:
[[1]]
示例 5:
- 输入:
candidates = [1],target = 2 - 输出:
[[1,1]]
问题分析
本题需要从给定的无重复元素正整数数组 “candidates” 里,挖掘出所有数字之和等于正整数 “target” 的独特组合,同时数组内数字可无限制重复选用。这是一道典型的组合搜索类问题,核心解题思路聚焦于 “搜索回溯” 策略,比较容易想到且易于实现的方法就是构造二叉树,并且用递归的方式进行遍历。
关键在于定义递归函数 dfs (target,combine,idx),按照深度优先搜索遍历可能的结果。同时我们初步分析一下终止条件设定,一旦 target 值小于等于 0,意味着组合已达或超出目标和,无需继续;或者 idx 超出数组边界、数组被 “用尽”,搜索便走到尽头。在递归步骤中,既可选跳过 idx 位数字,调用 dfs (target,combine,idx + 1),探索后续新元素组合可能;也能取用 idx 位数字,借 dfs (target - candidates [idx],combine,idx) 多次复用当前字符。树形展开、层层递进又按需回溯的机制,可以罗列所有可行解。
参考核心代码
all_res = []
def dfs(combine,target,idx,candidates):
if target == 0:
all_res.append(combine)
return
if target<0 or idx>=len(candidates):
return
dfs(combine+[candidates[idx]],target-candidates[idx],idx,candidates)
dfs(combine,target,idx+1,candidates)
def combinationSum(candidates, target):
if target<=0 or len(candidates) == 0:
return []
idx = 0
dfs([candidates[0]],target-candidates[0],idx,candidates)
dfs([],target,idx+1,candidates)
return all_res
代码分析
首先考虑特殊情况,即当需要搜索的目标值是0,或者可候选的成员数长度为0时,不存在任何组合,直接返回空列表。否则,由入口程序执行dfs递归的第一步。
该逻辑是将所有的数值分为两种操作可能(构造二叉树),即选择当前数值和不选择当前数值(指针移动到下一个数值)。其中,idx 定位在 “candidates” 数组当下所考察的位置索引,target 量化剩余待组合达成的数值额度,combine 则忠实记录已挑选组合的数字列表。如果数值被选中,则target-被选中的数值 后传递到下一级dfs,再由下一级dfs决定是否继续选择当前数值。
当target = 0时,遍历的元素刚好能凑成target,否则小于零则代表凑过头了,也有可能是根据搜索策略已经没有可供选择的候选数值了,则代表此路不通,搜索结束。
最后将每一条路线的combine值记录在all_res中 按数组输出即可。