day27|回溯法3-组合求和&回文子串

复习回溯法结构

在求解组合问题之前,需要将组合问题的树形图找出来,找出来树形图之后,再使用回溯法的结构模板进行求解。回溯算法的模板结构如下所示。
回溯三部曲:

  1. 确定函数的参数和返回值 ,函数的返回值一般来说是void类型
  2. 确定终止条件 ,if的终止逻辑
  3. 确定单层搜索的逻辑 ,for循环+处理结点+递归函数+撤销结点

39. 组合总和

**注意:**元素可以重复使用,剩余的节点中需要包括本次的元素
在这里插入图片描述
本题是 集合里元素可以用无数次,那么和组合问题的差别 其实仅在于 startIndex上的控制

  1. 在组合问题中,传入的startIndex是 i+1 ,因为之前出现过的节点,此后就不能出现了。
  2. 在组合问题的和中,传入的startIndex是 i ,因为需要能够访问该结点
class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        # 注意可以使用多次
        # 回溯的步骤复习
        # if终止条件,if中放置相应的结果集
        # 回溯函数中存放 for循环:处理结点-递归函数-撤销结点
        result = []
        path = []
        # 进行单层的递归
        def traversal(index):
            if sum(path) == target:
                result.append(path.copy())
                return 
            # 进行剪枝,如果大于就不再乡向下继续进行查找。
            if sum(path) > target:
                return 
            # 不同之处在于,传入的startIndex的值不同
            for i in range(index,len(candidates)):
                path.append(candidates[i])
                traversal(i)
                path.pop()
            return 
        traversal(0)
        return result

40.组合总和II(排序+回溯)

思路: 搜索过程中的进行去重,之前出现过的元素

  1. 树层去重:
  2. 树枝去重:used数组,记录当前结点是否搜索过
    树枝上可以重复取,树层上不可以重复取,因而本题的关键在于数层上的去重,而不是数枝的去重
    树层去重: 在for循环中进行去重,如果当前结点和上一个节点相同,并且上一个节点没有被访问,这样就可以说明这个节点出现了重复。
    在这里插入图片描述
class Solution:
    def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
        # 不同之处在于需要对原来的数组进行排序的操作
        # 利用快速排序
        used = [0 for i in range(len(candidates))]
        result = []
        path = []
        candidates = sorted(candidates) # 先进行排序
        def traversal(index):
            if sum(path) == target:
                result.append(path.copy())
                return
            if sum(path) > target:
                return 
            for i in range(index,len(candidates)):
            	# 树层去重的逻辑
                if i >= 1 and candidates[i] == candidates[i-1] and used[i-1] == 0:
                    continue
                path.append(candidates[i])
                used[i] = 1
                traversal(i+1)
                path.pop()
                used[i] = 0
            return 
        traversal(0)
        return result

131.分割回文串

在这里插入图片描述

切割问题,非常类似于组合问题。
代码里面什么表示切割线
(startIndex,i] 即为子串

// 确定递归的参数和返回值
// 全局变量 一维数组path:收集单一结果
//         二维数组result:将符合条件的结果储存起来
void backTracking(s,startIndex):
// startIndex就是表示切割的线,如果切割线走到了末尾,那么该结果进行判断
	if startIndex >= s.size:
		result.append(s)
		return 
	for(i=startIndex,i<s.size,i++){
		s = s[startIndex:i]
		ifhuiwen(s)
		  backTracking(s,i+1)
		// 再进行回溯求解。
		
	}

整体思路:

  1. 如何遍历所有可以切割的位置:将startIndex转化成切割的位置,然后利用i进行比遍历,每次返回一个子串即可。
  2. 返回的过程中需要进行剪枝操作,只有当前的子串是回文串,才可以继续向下进行搜寻。
  3. 利用while循环判断当前子串是否为回文子串。
class Solution:
    def partition(self, s: str) -> List[List[str]]:
        # 回溯法分割回文子串
        result = []
        path = []
        def isPalindrome(s,start,end):
            # 判断是否为回文子串
            while start < end :
                if s[start] != s[end]:
                    return False
                start += 1
                end -= 1
            return True
        
        def backtracking(s,startIndex):
            if startIndex >= len(s):
                result.append(path.copy())
                return 
            for i in range(startIndex,len(s)):
                if isPalindrome(s,startIndex,i):
                    path.append(s[startIndex:i+1])
                    backtracking(s,i+1)
                    path.pop()
                else:
                    continue
        backtracking(s,0)
        return result
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值