代码随想录算法训练营第二十三天 |回溯算法part02
39 组合总和
思路:依旧采用回溯的思路,不过之前的回溯时,都有一个index+1,这个时候就不能用了,因为要重复的使用。
但是依旧需要有一个start来控制起始位置,因为是组合问题,比如说 2 -> 2 -> 3 之后就不能有 2 -> 3 -> 2了,3后面只能是其他的数了。
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
result = []
path = []
sum_ = 0
candidates.sort()
self.backtracking(candidates,target,sum_,path,result,0)
return result
def backtracking(self,candidates,target,sum_,path,result,start):
if sum_ == target:
result.append(path[:])
return
if sum_ > target:
return
for i in range(start,len(candidates)):
if sum_ + candidates[i] > target:
break
path.append(candidates[i])
self.backtracking(candidates,target,sum_+candidates[i],path,result,i)
path.pop()
40 组合总和II
思路:和上一题几乎一模一样,就是多了一个判断的条件,因为每个数只能出现一次,那么就需要用index+1了。
另外,也有可能出现 1 1 2 和 2 1 1 这种情况,所以就需要进行如下判断:
if i > start and candidates[i] == candidates[i-1]:
continue
那么为什么是这个呢?
i > start: 这个条件保证只有当 i 的值大于 start 时,才会进行检查。这是因为我们希望在每一层递归中,只有当前的元素与前一个元素相等时,才进行跳过处理,而第一个元素(即 i == start)不需要与前一个元素比较。
candidates[i] == candidates[i-1] : 这个条件检查当前元素 candidates[i] 是否与前一个元素 candidates[i-1] 相同。如果相同,意味着当前元素已经在之前的路径中出现过,跳过当前元素可以避免产生重复的组合。
比如说 1 1 2 3,我刚开始遍历了1了,然后到了第2个1 我就不遍历了,完整代码如下:
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
candidates.sort()
path = []
result = []
self.backtracking(candidates,path,0,result,0,target)
return result
def backtracking(self,candidates,path,start,result,sum_,target):
if sum_ == target:
result.append(path[:])
return
for i in range(start,len(candidates)):
if sum_ + candidates[i] > target:
break
# if i > start and candidates[i] == candidates[i-1]:
# continue
path.append(candidates[i])
self.backtracking(candidates,path,i+1,result,sum_+candidates[i],target)
path.pop()
131 分割回文串
思路:首先应该得写一个判断是不是回文串的函数,然后对s进行递归遍历,比如说 a , a -> a , a -> a -> b,然后每一次都进行判断,如果是回文串的话就加入到result
def backtracking(self,s,result,path,index):
if len(s) == index:
result.append(path[:])
return
for i in range(index,len(s)):
if s[index:i+1] == s[index:i+1][::-1]:
path.append(s[index:i+1])
self.backtracking(s,result,path,i+1)
path.pop()
总结:也做了6道回溯的题了,是时候小小总结一下了。
对于回溯的题目,我觉得按照三步走是完全足够的。
确定参数,确定何时return,确定循环
一定要确认好循环的范围,以及递归时,用的是i+1还是i。
如果题目给定数据可以重复,那么就是用i,如果不重复就是用i+1。
为什么不是index+1呢,因为Index决定着我们进入循环的下界,我们使用i就是在选定了index的前提下,在选择别的数的。所以index 和 i 分别承担不同的任务,index选择一个基准,i决定往哪走。