39. 组合总和
Posted 炫云云
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了39. 组合总和相关的知识,希望对你有一定的参考价值。
39. 组合总和
给定一个无重复元素的正整数数组 candidates
和一个正整数 target
,找出 candidates
中所有可以使数字和为目标数 target
的唯一组合。
candidates
中的数字可以无限制重复被选取。如果至少一个所选数字数量不同,则两种组合是唯一的。
对于给定的输入,保证和为 target
的唯一组合数少于 150
个。
示例
输入: candidates = [2,3,6,7], target = 7
输出: [[7],[2,2,3]]
输入: candidates = [2,3,5], target = 8
输出: [[2,2,2,2],[2,3,3],[3,5]]
输入: candidates = [2], target = 1
输出: []
输入: candidates = [1], target = 1
输出: [[1]]
回溯算法
根据示例 1:输入: candidates = [2, 3, 6, 7]
,target = 7
。
- 候选数组里有
2
,如果找到了组合总和为7 - 2 = 5
的所有组合,再在之前加上2
,就是7
的所有组合; - 同理考虑
3
,如果找到了组合总和为7 - 3 = 4
的所有组合,再在之前加上3
,就是7
的所有组合,依次这样找下去。
通过回溯算法找出所有组合:
- 以
target = 7
为 根结点 ,创建一个分支的时 做减法 ; - 每一个箭头表示:从父亲结点的数值减去边上的数值,得到孩子结点的数值。边的值就是题目中给出的
candidate
数组的每个元素的值; - 减到 0或者负数的时候停止,即:结点 0 和负数结点成为叶子结点;
- 所有从根结点到结点 0的路径(只能从上往下,没有回路)就是题目要找的一个结果。
析重复路径产生的原因
产生重复的原因是:在每一个结点,做减法,展开分支的时候,由于题目中说 每一个元素可以重复使用,我们考虑了 所有的 候选数,因此出现了重复的列表。
可不可以在搜索的时候就去重呢?答案是可以的。遇到这一类相同元素不计算顺序的问题,我们在搜索的时候就需要 按某种顺序搜索。
具体的做法是:每一次搜索的时候设置 下一轮搜索的起点 index
,已经考虑过的数,以后的搜索中就不能出现,让我们的每次搜索都从当前起点往后搜索(包含当前起点),直到搜索到数组末尾。这样我们人为规定了一个搜索顺序,就可以避免重复方案。
即:从每一层的第 2 个结点开始,都不能再搜索产生同一层结点已经使用过的 candidate
里的元素。
算法
定义递归函数 dfs(target, index)
表示当前在 candidates
数组的第 index
位,还剩 target
要组合,已经组合的列表为 combine
。递归的终止条件为 target <= 0
或者 candidates
数组被全部用完。
那么在当前的函数中,每次我们可以选择跳过不用第 index
个数,即执行 dfs(target, index+ 1)
。
也可以选择使用第 index
个数,即执行 dfs(target - candidates[index], index)
,注意到每个数字可以被无限制重复选取,因此搜索的下标仍为 index
。
class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
n = len(candidates)
combine =[]
ans= []
def dfs(target , index):
if index == n:
return
if target ==0:
ans.append(combine[:])
return
# 选择当前数,即重复选择
if target - candidates[index] >=0:
combine.append(candidates[index])
dfs(target- candidates[index],index)
combine.pop()
dfs(target, index+1) # 直接跳过
dfs(target, 0)
return ans
class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
n = len(candidates)
combine =[]
ans= []
def dfs(target , index):
if index == n:
return
if target ==0: # 等于零说明结果符合要求
ans.append(combine[:])
return
for i in range(index, n): # 等于零说明结果符合要求
# 如果candidates大于目标值,则差为负数,不符合结果
if target - candidates[i] >=0:
combine.append(candidates[i])
dfs(target- candidates[i],i) # 目标值减去元素值
combine.pop()
dfs(target, 0)
return ans
以上是关于39. 组合总和的主要内容,如果未能解决你的问题,请参考以下文章