LeetCode 131题详解:高效分割回文串的递归与动态规划方法

简介: LeetCode 131题详解:高效分割回文串的递归与动态规划方法

❤️❤️❤️ 欢迎来到我的博客。希望您能在这里找到既有价值又有趣的内容,和我一起探索、学习和成长。欢迎评论区畅所欲言、享受知识的乐趣!

期待与您一起探索技术、持续学习、一步步打怪升级 欢迎订阅本专栏❤️❤️

在本篇文章中,我们将详细解读力扣第 131 题“分割回文串”。该问题在字符串处理和动态规划中非常常见,通过学习本篇文章,读者将掌握高效解决此类问题的技巧。

问题描述

力扣第 131 题“分割回文串”描述如下:

给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是回文串。返回 s 所有可能的分割方案。

示例 1:

输入: "aab"
输出: [["a","a","b"],["aa","b"]]

示例 2:

输入: "a"
输出: [["a"]]

解题思路

  1. 初步分析
  • 我们需要将字符串 s 分割成一些子串,使每个子串都是回文串。
  • 回文串是指正读和反读都相同的字符串。
  1. 递归+回溯法
  • 我们可以用递归+回溯的方法来解决这个问题。
  • 从字符串的第一个字符开始,逐个尝试分割,如果前面的部分是回文,则继续分割剩下的部分。
  • 通过回溯来记录每次分割的结果。
  1. 动态规划法
  • 我们还可以用动态规划来优化判断回文的过程。
  • 预先计算并存储所有子串是否为回文串,避免重复判断。

解法一:递归+回溯法

  1. 步骤
  • 从字符串的第一个字符开始,逐个尝试分割。
  • 每次分割后,判断前面的部分是否为回文。
  • 如果是回文,则递归处理剩下的部分。
  • 通过回溯来记录每次分割的结果。
  1. 伪代码
def backtrack(start, path):
    if start == len(s):
        result.append(path)
        return
    for end in range(start, len(s)):
        if is_palindrome(s, start, end):
            backtrack(end + 1, path + [s[start:end + 1]])

代码实现

解法一:递归+回溯法
def partition(s):
    def is_palindrome(sub_s):
        return sub_s == sub_s[::-1]
    def backtrack(start, path):
        if start == len(s):
            result.append(path[:])
            return
        for end in range(start, len(s)):
            if is_palindrome(s[start:end + 1]):
                backtrack(end + 1, path + [s[start:end + 1]])
    
    result = []
    backtrack(0, [])
    return result

复杂度分析

  • 时间复杂度:O(N * 2^N),其中 N 是字符串的长度。每个字符都有分割和不分割两种选择。
  • 空间复杂度:O(N),用于递归调用的栈空间。

代码优化

解法二:动态规划法
  1. 步骤
  • 预先计算并存储所有子串是否为回文串。
  • 使用动态规划表 dp,其中 dp[i][j] 表示字符串 s 的子串 s[i:j+1] 是否为回文。
  • 使用回溯法来找到所有分割方案。
  1. 伪代码
def partition(s):
    dp = [[False] * len(s) for _ in range(len(s))]
    for right in range(len(s)):
        for left in range(right + 1):
            if s[left] == s[right] and (right - left <= 2 or dp[left + 1][right - 1]):
                dp[left][right] = True
    def backtrack(start, path):
        if start == len(s):
            result.append(path[:])
            return
        for end in range(start, len(s)):
            if dp[start][end]:
                backtrack(end + 1, path + [s[start:end + 1]])

代码实现

解法二:动态规划法
def partition(s):
    n = len(s)
    dp = [[False] * n for _ in range(n)]
    # 填充动态规划表
    for right in range(n):
        for left in range(right + 1):
            if s[left] == s[right] and (right - left <= 2 or dp[left + 1][right - 1]):
                dp[left][right] = True
    def backtrack(start, path):
        if start == n:
            result.append(path[:])
            return
        for end in range(start, n):
            if dp[start][end]:
                backtrack(end + 1, path + [s[start:end + 1]])
    
    result = []
    backtrack(0, [])
    return result

复杂度分析

  • 时间复杂度:O(N^2) 计算动态规划表需要 O(N^2) 的时间,回溯的时间复杂度在最坏情况下仍为 O(N * 2^N)。
  • 空间复杂度:O(N^2) 用于存储动态规划表。

测试案例

def test_partition():
    assert partition("aab") == [["a","a","b"], ["aa","b"]]
    assert partition("a") == [["a"]]
    assert partition("racecar") == [["r","a","c","e","c","a","r"], ["r","aceca","r"], ["racecar"]]
    assert partition("aaa") == [["a","a","a"], ["a","aa"], ["aa","a"], ["aaa"]]
test_partition()

总结

本文详细解读了力扣第 131 题“分割回文串”,通过递归+回溯法和动态规划法两种不同的解法,帮助读者深入理解算法问题的解决思路。希望读者通过本文的学习,能够在力扣刷题的过程中更加得心应手。

参考资料

  • 《算法导论》—— Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, Clifford Stein
  • 力扣官方题解

🌹🌹如果觉得这篇文对你有帮助的话,记得一键三连关注、赞👍🏻、收藏是对作者最大的鼓励,非常感谢 ❥(^_-)

❤️❤️作者知识有限,如有错误,请各位大佬评论区批评指正,不胜感激❥(^_-)

欢迎关注微信公众号 数据分析螺丝钉

相关文章
|
11天前
|
算法 Python
LeetCode 常用方法
LeetCode 常用方法
|
15天前
|
存储 算法 数据可视化
【模拟面试问答】深入解析力扣164题:最大间距(桶排序与排序方法详解)
【模拟面试问答】深入解析力扣164题:最大间距(桶排序与排序方法详解)
|
15天前
|
存储 算法 数据可视化
深入解析力扣161题:相隔为 1 的编辑距离(逐字符比较与动态规划详解)
深入解析力扣161题:相隔为 1 的编辑距离(逐字符比较与动态规划详解)
|
15天前
|
存储 算法 数据可视化
力扣156题最全解法:如何上下翻转二叉树(递归与迭代方法详解,附图解)
力扣156题最全解法:如何上下翻转二叉树(递归与迭代方法详解,附图解)
|
15天前
|
SQL 算法 数据挖掘
深入解析力扣183题:从不订购的客户(LEFT JOIN与子查询方法详解)
深入解析力扣183题:从不订购的客户(LEFT JOIN与子查询方法详解)
|
15天前
|
算法 数据挖掘 大数据
深入解析力扣172题:阶乘后的零(计算因子5的方法详解及模拟面试问答)
深入解析力扣172题:阶乘后的零(计算因子5的方法详解及模拟面试问答)
|
15天前
|
存储 算法 数据可视化
深入解读力扣154题:寻找旋转排序数组中的最小值 II(多种方法及详细ASCII图解)
深入解读力扣154题:寻找旋转排序数组中的最小值 II(多种方法及详细ASCII图解)
|
15天前
|
存储 算法 数据可视化
|
15天前
|
存储 算法 数据可视化
LeetCode 132题详解:使用动态规划与中心扩展法解决分割回文串 II 的最少分割次数问题
LeetCode 132题详解:使用动态规划与中心扩展法解决分割回文串 II 的最少分割次数问题
【42页动态规划学习笔记分享】动态规划核心原理详解及27道LeetCode相关经典题目汇总(4)
【42页动态规划学习笔记分享】动态规划核心原理详解及27道LeetCode相关经典题目汇总