Day26
39. 组合总和
题意:
给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的数字可以无限制重复被选取。 target都是正整数
示例 1:
- 输入:candidates = [2,3,6,7], target = 7,
- 所求解集为: [ [7], [2,2,3] ]
思路:
这道题和之前的区别在于可以多次甚至无限次的选取同一个数,同时因为这些数都大于0或者说都是正整数,所以终止条件就是大于target就可以终止
剪枝:如果for循环中本层的sum已经大于target了,就不需要再进行回溯了
class Solution:
def __init__(self):
self.res = []
self.path = []
def backtracking(self, target, candidates):
if sum(self.path) > target:
return
if sum(self.path) == target:
self.res.append(self.path[:])
return
for i in range(len(candidates)):
self.path.append(candidates[i])
self.backtracking(target, candidates[i:]) # 继续回溯也可以是包含i及i以后的元素
# 关键点:不用i+1了,表示可以重复读取当前的数
self.path.pop()
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
self.backtracking(target, candidates)
return self.res
40.组合总和II
题意:
给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。candidates 中的每个数字在每个组合中只能使用一次。
示例:
输入: candidates = [10,1,2,7,6,1,5], target = 8
输出:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]
本题的难点在于区别2中:集合(数组candidates)有重复元素,但还不能有重复的组合。
如果一开始把所有组合求出来再去重的这种做法很容易超时,所以要在回溯过程中就把重复组合删除
思路(也是去重的一个经典写法):需要一个bool used数组来证明是否用过这个元素;同时需要进行以下判断:
有两种维度的使用过:
- 同一组合内部(树枝)使用过:可以 nums[i]==nums[i-1] and used[i-1]=True
- 同一树层使用过:不可以nums[i-1] and used[i-1]=False
- 也用1112这种试过了,不仅是顶层数层去重,每一小层也都可以去重
class Solution:
def __init__(self):
self.res = []
self.path = []
'''这道题涉及到可以树枝重复,不能数层重复的问题'''
def backtracking(self, target, start_index, candidates, used):
if sum(self.path) == target:
self.res.append(self.path[:])
return
if sum(self.path) > target:
return
for i in range(start_index, len(candidates)):
if i>0 and candidates[i-1]==candidates[i] and used[i-1]==False:
continue
self.path.append(candidates[i])
used[i] = True
self.backtracking(target, i+1, candidates, used)
# print(i, candidates[i], self.path)
used[i] = False
self.path.pop()
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
used = [False] * len(candidates)
self.backtracking(target, 0, sorted(candidates), used)
return self.res
131.分割回文串
涉及到切割的问题跟如何判断回文的问题,首次遇到分割问题
class Solution:
def __init__(self):
self.res = []
self.path = []
def isPalindrome(self, s):
if s == s[::-1]:
return True
else:
return False
def backtracing(self, start_index, s):
if start_index == len(s):
self.res.append(self.path[:])
return
for i in range(start_index, len(s)):
part = s[start_index:i+1]
if self.isPalindrome(part):
self.path.append(part)
self.backtracing(i+1, s)
self.path.pop()
def partition(self, s: str) -> List[List[str]]:
self.backtracing(0, s)
return self.res