131. 分割回文串

最朴素的回溯

直接写了一个朴素的回溯,无剪枝也无优化的

class Solution:
    def partition(self, s: str) -> List[List[str]]:
        self.ans = []
        self.back(s,[]) 
        
        return self.ans
        
    def back(self,s,lst):
        if s == '':
            self.ans.append(lst.copy())
            return  

        for i in range(len(s)):
            # 左半部分
            left = s[:i+1] 
            # 如果是回文
            if self.judge(left):
                # 添加
                lst.append(left)
                # 处理右半部分
                right = self.back(s[i+1:],lst)
                lst.pop()

    def judge(self,s):
        for i in range(len(s)//2):
            if s[i] != s[len(s)-i-1]:
                return False
        return True

在这里插入图片描述
AC了

题解

题解的方法有两种

回溯+动态规划

主要是优化了判断回文的过程,和 5. 最长回文子串 - 力扣(LeetCode) (leetcode-cn.com) 的做法很相像

答案

class Solution:
    def partition(self, s: str) -> List[List[str]]:
        n = len(s)
        f = [[True] * n for _ in range(n)]
		# 判断可能存在的回文子串
        for i in range(n - 1, -1, -1):
            for j in range(i + 1, n):
                f[i][j] = (s[i] == s[j]) and f[i + 1][j - 1]

        ret = list()
        ans = list()

        def dfs(i: int):
            if i == n:
                ret.append(ans[:])
                return
            
            for j in range(i, n):
				# 避免调用judge重复验证
                if f[i][j]:
                    ans.append(s[i:j+1])
                    dfs(j + 1)
                    ans.pop()

        dfs(0)
        return ret

回溯+记忆化搜索

class Solution:
    def partition(self, s: str) -> List[List[str]]:
        n = len(s)

        ret = list()
        ans = list()

        @cache
        def isPalindrome(i: int, j: int) -> int:
            if i >= j:
                return 1
            return isPalindrome(i + 1, j - 1) if s[i] == s[j] else -1

        def dfs(i: int):
            if i == n:
                ret.append(ans[:])
                return
            
            for j in range(i, n):
                if isPalindrome(i, j) == 1:
                    ans.append(s[i:j+1])
                    dfs(j + 1)
                    ans.pop()

        dfs(0)
        isPalindrome.cache_clear()
        return ret

方法一中的动态规划预处理计算出了任意的 s[i…j]s[i…j] 是否为回文串,但在实际的搜索过程中,并不是每个 ss 的子串都是会被搜索到的,因此我们可以将这一步改为记忆化搜索,减少算法的常数。

这个@cache是python 3.9的新功能,加上它之后,计算过程中的结果都保存在缓存中,每次调用函数前先查看缓存,具体见文档:
https://docs.python.org/zh-cn/3/library/functools.html

这段代码相当于优化了判断回文的次数

总结

朴素回溯:
最直观的想法,回溯+O(n)时间判断回文
回溯+DP:
避免O(n)时间判断回文的开销,先DP走一遍,得到所有回文的结果
回溯+记忆化搜索:
在方法二的基础上提升,避免判断所有DP

回溯的时间开销是O(2^n),这是无法避免的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值