代码随想录算法训练营Day27
39. Combination Sum
class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
ans = []
def backtrack(path: List[int], sumCur: int, startIndex: int):
print(path)
if sumCur == target:
ans.append(path[:])
return
elif sumCur > target:
return
for ii in range(startIndex, len(candidates)):
path.append(candidates[ii])
backtrack(path, sumCur+candidates[ii], ii)
path.pop()
backtrack([], 0, 0)
return ans
# 关注如何去重
40. Combination Sum II
都知道组合问题可以抽象为树形结构,那么“使用过”在这个树形结构上是有两个维度的,一个维度是同一树枝上使用过,一个维度是同一树层上使用过。没有理解这两个层面上的“使用过” 是造成大家没有彻底理解去重的根本原因。
那么问题来了,我们是要同一树层上使用过,还是同一树枝上使用过呢?
回看一下题目,元素在同一个组合内是可以重复的,怎么重复都没事,但两个组合不能相同。
所以我们要去重的是同一树层上的“使用过”,同一树枝上的都是一个组合里的元素,不用去重。
class Solution:
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
candidates.sort()
# 回溯算法
ans = []
def backtrack(path: List[int], sumCur: int, startIndex: int):
if sumCur == target:
ans.append(path[:])
return
elif sumCur > target:
return
for ii in range(startIndex, len(candidates)):
if ii > startIndex and candidates[ii] == candidates[ii-1]:
continue
path.append(candidates[ii])
backtrack(path, sumCur+candidates[ii], ii+1)
path.pop()
backtrack([], 0, 0)
return ans
# 如何去重: [注意要先排序], 我们要去重的是同一树层上的“使用过”
先对数组 升序 排序,重复的元素一定不是排好序以后相同的连续数组区域的第 1 个元素。也就是说,剪枝发生在:**同一层数值相同的结点第 2、3 … 个结点,因为数值相同的第 1 个结点已经搜索出了包含了这个数值的全部结果. **
131. Palindrome Partitioning
class Solution:
def partition(self, s: str) -> List[List[str]]:
ans = []
def isPalindrome(s:str) -> bool:
ii, jj = 0, len(s)-1
while ii < jj:
if s[ii] != s[jj]:
return False
ii += 1
jj -= 1
return True
def backtrack(path: List[str], startIndex: int):
if startIndex >= len(s):
ans.append(path[:])
return
for ii in range(startIndex, len(s)):
if isPalindrome(s[startIndex:ii+1]):
path.append(s[startIndex:ii+1])
backtrack(path, ii+1)
path.pop()
backtrack([], 0)
return ans
ans.append(path[:])