39. 组合总和
思路
:
题目:重复选取,警惕0,如果有0就是死循环了,(已知所有元素都为正整数没有重复元素)
元素可以重复使用,树的深度怎么确定:
这里与前面的不同主要是在选择了一个数时,下一次要选的列表也包含这个数
步骤:
确定函数返回值;
确定终止条件;
单层搜索逻辑
伪代码(C++)
:
void backtracking(candidate,target,sum,startIndex){ //startindex下一循环的初始位置
if(sum > target){
return
}
if(sum==target){
result.push_back(path);
return;
}
for (int i = startIndex; i < candidates.size(); i++) { // 单层搜索逻辑
sum += candidates[i];
path.push_back(candidates[i]);
backtracking(candidates, target, sum, i); // 关键点:不用i+1了,表示可以重复读取当前的数
sum -= candidates[i]; // 回溯
path.pop_back(); // 回溯
}
}
python代码
:
class Solution:
def backtracking(self, candidates, target, sum, startIndex):
if sum>target:
return
if sum == target:
self.result.append(self.path[:])
return
for i in range(startIndex, len(candidates)):
self.path.append(candidates[i])
sum += candidates[i]
self.backtracking(candidates, target, sum, i)
sum -= candidates[i]
self.path.pop()
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
self.result = []
self.path = []
self.backtracking(candidates, target, 0, 0)
return self.result
剪枝操作
先排序,剪枝大于最大值的部分
40.组合总和II
思路
:
与上题相比不能重复,但candidate中存在重复的数,解集不能包含重复的组合。
树层去重的话,需要对数组排序!
伪代码(C++)
:
// path一维数组
// result二维数组
python代码
:
class Solution:
def backtracking(self, candidates, target, sum, startIndex):
if sum>target:
return
if sum == target:
self.result.append(self.path[:])
return
for i in range(startIndex, len(candidates)):
if i > startIndex and candidates[i] == candidates[i - 1]:
continue
self.path.append(candidates[i])
sum += candidates[i]
self.backtracking(candidates, target, sum, i+1)
sum -= candidates[i]
self.path.pop()
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
self.result = []
self.path = []
candidates.sort()
self.backtracking(candidates, target, 0, 0)
return self.result
131.分割回文串
class Solution:
def partition(self, s: str) -> List[List[str]]:
'''
递归用于纵向遍历
for循环用于横向遍历
当切割线迭代至字符串末尾,说明找到一种方法
类似组合问题,为了不重复切割同一位置,需要start_index来做标记下一轮递归的起始位置(切割线)
'''
result = []
self.backtracking(s, 0, [], result)
return result
def backtracking(self, s, start_index, path, result ):
# Base Case
if start_index == len(s):
result.append(path[:])
return
# 单层递归逻辑
for i in range(start_index, len(s)):
# 此次比其他组合题目多了一步判断:
# 判断被截取的这一段子串([start_index, i])是否为回文串
if self.is_palindrome(s, start_index, i):
path.append(s[start_index:i+1])
self.backtracking(s, i+1, path, result) # 递归纵向遍历:从下一处进行切割,判断其余是否仍为回文串
path.pop() # 回溯
def is_palindrome(self, s: str, start: int, end: int) -> bool:
i: int = start
j: int = end
while i < j:
if s[i] != s[j]:
return False
i += 1
j -= 1
return True