39 组合总和
给你一个 无重复元素 的整数数组 candidates
和一个目标整数 target
,找出 candidates
中可以使数字和为目标数 target
的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。
candidates
中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。
对于给定的输入,保证和为 target
的不同组合数少于 150
个。
示例 1:
输入:candidates =[2,3,6,7],
target =7
输出:[[2,2,3],[7]] 解释: 2 和 3 可以形成一组候选,2 + 2 + 3 = 7 。注意 2 可以使用多次。 7 也是一个候选, 7 = 7 。 仅有这两种组合。
这个题 和组合问题很像,而且无重复数字,且同一个数字可以无限制重复被选取。
一个数字可以被重复选,说明我们纵向遍历,所访问的数字还是candidates,不需要startindex + 1
同样的,回溯三部曲
1. 回溯函数的参数:
candidates ,target, path用来存放结果 startIndex result 结果集
2.回溯函数的中止条件
1. 当累计和大于 cursum的时候就可以返回了
2. 当累计和等于target 也可以返回了
3. 单层回溯
1. 求和 判断是否等于 target 等于的化,加入result ,return
2. 横向遍历
path.append()
纵向递归
回溯
class Solution:
def combinationSum2(self, candidates: List[int], target: int):
result = []
path = []
self.backtracking(candidates, target, 0, path, result)
return result
def backtracking(self, candidates, target, startIndex, path, result):
if sum(path) > target:
return
if sum(path) == target:
result.append(path[:])
return
for i in range(startIndex, len(candidates)):
path.append(candidates[i])
self.backtracking(candidates, target, i, path, result)
path.pop()
40 组合总和II
给定一个候选人编号的集合 candidates
和一个目标数 target
,找出 candidates
中所有可以使数字和为 target
的组合。
candidates
中的每个数字在每个组合中只能使用 一次 。
注意:解集不能包含重复的组合。
这个题目,candidate中的数字是可以重复,但是解决中不能重复,我们要去重
比如 1 1 2 target为3,如果按照组合的思路,会产生两个1 2 1 2的组合。
这里就需要去重,思路就是如果前面已经出现过了,我就跳过,比如这里第一个1 已经走完了一个纵向的遍历,当我第二个1的时候就不用走了,那就是 candidates[i] == candidates[i-1]
但回溯远远没有这么简单,这个i是所有的i都可以吗,我们第一反应是i>0,如果是这样,我就直接跳过。但这样是有问题的,假设 1 1 2 target 2,会直接跳过1,1.
其实,这里,我们要明白 我们要跳过的是横向遍历中的重复,而不是纵向遍历中的重复
那么怎么跳过横向遍历中的重复呢,i>0肯定不行,其实是换成i>startIndex就可以了
为什么?
看如下一个回溯的模板代码,如果向下递归,startIndex每次向下一层都会+1,i又从startIndex开始,一直向下递归的化不可能有i>startIndex! 这符合我们的纵向遍历中如果重复,我们不去管。
但是如果是横向遍历,i 是从 startIndex 到len()取值,startIndex 固定,i+1,那么,i就会存在i>startindex。这就是我们要处理的情况了!
for i in range(startIndex, len(candidates)):
if i > startIndex and candidates[i] == candidates[i-1] :
continue
path.append(candidates[i])
self.backtracking(candidates, target, i+1, used, path, result)
path.pop()
完整的代码如下
class Solution:
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
path = []
result = []
self.backtracking(candidates, target, 0, path, result)
return result
def backtracking(self, candidates, target, startIndex, path, result):
if sum(path) > target:
return
if sum(path) == target:
result.append(path[:])
return
for i in range(startIndex, len(candidates)):
if (i > startIndex) and candidates[i] == candidates[i-1]:
continue
path.append(candidates[i])
self.backtracking(candidates, target, i+1, path, result)
path.pop()
131 分割回文串
给你一个字符串 s
,请你将 s
分割成一些子串,使每个子串都是
回文串。返回 s
所有可能的分割方案。
示例 1:
输入:s = "aab" 输出:[["a","a","b"],["aa","b"]]
这个题,没有叫你返回所有符合的字串,只是叫你返回分割的方案。
比如他的示例,从a开始分割, 从aa开始分割。没有叫你将所有的符合要求的回文串返回
是让你返回分割后,各部分仍然是回文串的方式!
同样,也可以看作是组合问题
横向遍历是我们的字符串,但是又startIndex递增,取字符的时候
纵向遍历也是index+1
模板解决 回溯三部曲
1. 递归参数
s,startIndex, path, result
2. 递归中止条件:
如果纵向遍历已经遍历到底部,说明已经分割完了,直接将结果加进去
3. 单层搜索
横向 遍历字符串
纵向 分割并判断字符是否回文
满足,加入path
向下递归
回溯
class Solution:
def partition(self, s: str) -> List[List[str]]:
result = []
self.backtracking(s, 0, [], result)
return result
def backtracking(self, s, startIndex, path, result):
if len(s) == startIndex:
result.append(path[:])
for i in range(startIndex, len(s)):
if self.is_match(s, startIndex, i):
path.append(s[startIndex: i+1])
self.backtracking(s, i+1, path, result)
path.pop()
def is_match(self, s, start, end):
i = start
j = end
while i < j:
if s[i] != s[j]:
return False
i += 1
j -= 1
return True