Leetcode39
给你一个 无重复元素 的整数数组 candidates
和一个目标整数 target
,找出 candidates
中可以使数字和为目标数 target
的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。
candidates
中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。
对于给定的输入,保证和为 target
的不同组合数少于 150
个。
思路:这道题和我们之前做过的组合题很类似,只不过这里有一个条件是,同一个数字可以无限制的重复使用,还记得我们之前题目中的递归参数写i的时候都是写的i+1,这就是直接i递归下一层,就是不会再次使用当前的数字,但是这里既然要求可以重复使用,那么就不用i+1了,直接递归i就可以了。
递归三部曲:
循环终止条件:
递归参数:一个startindex控制for循环的起始位置,sum用于求和,判断是否达到目标值。
那么对于组合问题,什么时候需要startIndex呢?
如果是一个集合来求组合的话,就需要startIndex,例如:77.组合 (opens new window),216.组合总和III (opens new window)。
如果是多个集合取组合,各个集合之间相互不影响,那么就不用startIndex,例如:17.电话号码的字母组合
单层循环逻辑:单层for循环依然是从startIndex开始,搜索candidates集合。注意:本题元素为可重复选取的。
所以我们的i 可以不用写成i+1
代码:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
path = []
result = []
def traversal(candidates,target,sum,index):
if sum > target:
return
if sum==target:
result.append(path[:])
return
for i in range(index,len(candidates)):
sum+=candidates[i]
path.append(candidates[i])
traversal(candidates,target,sum,i)
sum-=candidates[i]
path.pop()
traversal(candidates,target,0,0)
return result
Leetcode40组合总和
思路:本题的难点在于区别2中:集合(数组candidates)有重复元素,但还不能有重复的组合。
- 本题candidates 中的每个数字在每个组合中只能使用一次。
- 本题数组candidates的元素是有重复的,而39.组合总和 (opens new window)是无重复元素的数组candidates
这道题对比上面这道题多了一个限制,也就是只能使用一次,但是这个使用一次是怎么理解的呢?
我们转化为树形结构来看,有两个维度,一个是树的同一层,另一个是树的分支,也就是说树的分是可以取重复的,但是在树的同一层中,之前用过的就不能再用第二次了。
如图所示:
强调一下,树层去重的话,需要对数组排序!
回溯三部曲:
递归参数:这里还是设置一个index,然后一个sum来记录求和
递归终止条件:如果sum+candidates[I]>target,注意我们的数组已经是排好序了的,那么如果开头加上就已经大于target了,后面的也只会更大,就不用再继续了。
单层循环逻辑:如果循环到当前元素,判断是否和前面的元素一样,并且这里的i是大于0的哈。如果和前面元素一样的话continue,就相当于是跳过了本层的重复元素。
代码:
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
res = []
path = []
# used = len(candidates)*[False]
def traversal(candidates,target,sum,index):
#为了避免重复 需要对数组排序
candidates.sort()
if sum==target:
res.append(path[:])
for i in range(index,len(candidates)):
#如果当前相加 都大于target了 那就没必要往后了
#直接返回
if sum + candidates[i] > target:
return
#跳过同一个树层使用过的元素
if i > index and candidates[i] == candidates[i-1]:
continue
sum +=candidates[i]
path.append(candidates[i])
# used[i] = True
traversal(candidates,target,sum,i+1)
# used[i]=False
sum-=candidates[i]
path.pop()
traversal(candidates,target,0,0)
return res