算法训练第三十天 | 回溯算法 39. 组合总和 40.组合总和II 131.分割回文串

回溯算法

代码模板

思路就是通过横向for循环,纵向递归的形式(递归里面嵌for循环套)
在这里插入图片描述
代码模板如下

void backtracking(参数) {
    if (终止条件) {
        存放结果;
        return;
    }

    for (本层集合中元素(树中节点孩子的数量就是集合的大小)) {
        处理节点;
        backtracking(路径,选择的列表); // 递归
        回溯,撤销处理结果
    }
}

LeetCode 39. 组合总和

题目链接

39. 组合总和

思路

注意组合是没有顺序的 ,例如【2,3】和【3,2】是同一个
这题和77的区别就是,数字可重复

class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        path = []
        result = []
        def backtracking(candidates, target, startIndex):
            if sum(path) > target:
                return
            if sum(path) == target:
                result.append(path[:])
                return
            for i in range(startIndex, len(candidates)):
                path.append(candidates[i])
                backtracking(candidates, target, i)
                path.pop()
        backtracking(candidates, target, 0)
        return result

LeetCode 40.组合总和II

题目链接

40.组合总和II

思路

跟39的区别在于,39是同一个位置的数反复用,集合没有重复值,40是同一个位置的数只能用一次但是集合会有重复值
这题的难点是去重的逻辑,要对数值做标记,也就是定义一个标记集合来表示某个数是否被使用过

class Solution:
    def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
        #先做一个排序方便去重
        candidates = sorted(candidates)
        uesd = [False] * len(candidates)
        path = []
        result = []
        def backtracking(candidates, target, startIndex, uesd):
            if sum(path) > target: #剪枝
                return
            if sum(path) == target:
                result.append(path[:])
                return
            for i in range(startIndex, len(candidates)):
                #如果当前元素和上一个取的元素相同,去重
                if i>0 and candidates[i] == candidates[i-1] and uesd[i-1] == False:
                    continue
                path.append(candidates[i])
                uesd[i] = True
                backtracking(candidates, target, i+1, uesd)
                uesd[i] = False
                path.pop()
        backtracking(candidates, target, 0, uesd)
        
        return result

反思

在这里插入图片描述
感觉这个去重的逻辑还是不太理解,没明白是怎么想到,如果上一个值标记是0的时候就要跳过本次循环

LeetCode 131.分割回文串

题目链接

131.分割回文串

思路

依旧是回溯三部曲,需要注意的是存入path的内容前做一个回文判断,先切割判断是回文了再存,不是就直接continue掉

class Solution:
    def partition(self, s: str) -> List[List[str]]:
        path = []
        result = []
        
        def isPalindrome(s, startIndex, i):
            s = s[startIndex:i+1]
            
            if s == s[::-1]:
                return True
            else:
                return False
        
        def backtracking(s, startIndex):
            if startIndex >= len(s):
                result.append(path[:])
                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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值