当前位置: 首页 > news >正文

Leetcode132:分割回文串 II

题目描述:

给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是回文串。

返回符合要求的 最少分割次数 。

代码思路:

  1. 预处理字符串(使用Manacher算法的一部分)

    • 为了方便处理回文串(尤其是偶数长度的回文串),代码首先构造了一个新的字符串 ss。这个新字符串通过在原字符串 s 的每个字符之间以及开头和结尾插入特殊字符(这里是 #)来构造。
    • 这样做的好处是,无论是奇数长度还是偶数长度的回文串,在新字符串 ss 中都会以一个字符为中心形成对称。
  2. 使用Manacher算法计算回文半径

    • 接下来,代码利用Manacher算法的一个变种来计算新字符串 ss 中每个字符的回文半径,并将结果存储在数组 p 中。
    • p[i] 表示以 ss[i] 为中心的回文串的半径长度(注意,这里不包括中心字符本身)。
    • Manacher算法通过利用已知的回文信息来减少不必要的比较,从而提高效率。
  3. 转换回文半径为原始字符串的回文信息

    • 由于 ss 是通过在 s 的字符间插入 # 构造的,因此原始字符串 s 中的回文串信息可以通过 p 数组中的回文半径来计算。
    • 需要注意的是,ss 中的索引 j 和原始字符串 s 中的索引 i 之间存在对应关系,即 j = 2 * i + 1(因为我们在每个字符之间都插入了一个 #)。
    • 因此,当 ss 中的回文中心 j 的回文半径 p[j] 减去 1 后,它表示的是原始字符串 s 中以某个位置为中心的最长回文串的长度。
  4. 动态规划求解最少分割次数

    • 定义一个动态规划数组 dp,其中 dp[i] 表示字符串 s 的前 i 个字符所需的最少分割次数。
    • 初始化 dp[0] = -1(表示空字符串不需要分割)。
    • 然后,对于每个可能的子串 s[i:j](其中 i 从 1 到 n1j 从 i 到 n1),检查它是否是一个回文串。
    • 如果 s[i:j] 是回文串,则通过检查新字符串 ss 中对应回文中心 mid 的回文半径 p[mid] 是否覆盖 s[i:j] 来判断。具体来说,如果 p[mid] - 1 >= j - i + 1 成立,则说明 s[i:j] 是一个回文串。
    • 如果 s[i:j] 是回文串,则更新 dp[j] 为 dp[i-1] + 1 和当前 dp[j] 的较小值。这里 dp[i-1] + 1 表示在 i-1 位置之前的子串所需的最少分割次数加上当前这个回文子串的一次分割(实际上不需要真的进行分割,因为 s[i:j] 已经是一个完整的回文串了,但这里是为了保持动态规划的状态转移逻辑)。
  5. 返回结果

    • 最后,dp[-1] 存储了整个字符串 s 所需的最少分割次数(注意,由于 dp 数组的索引是从 0 开始的,而字符串 s 的长度是 n1,所以 dp[-1] 实际上对应的是 dp[n1],即整个字符串的最少分割次数)。

代码实现:

class Solution:
    def minCut(self, s: str) -> int:
        # Manacher模版
        ss = '#'
        for c in s:
            ss += c + '#'
        c = r = 0
        n = len(ss)
        p = [0] * n
        for i in range(n):
            k = min(p[2 * c - i],r - i) if i < r else 1
            while i - k >= 0 and i + k < n and ss[i - k] == ss[i + k]:
                k += 1
            p[i] = k
            if i + k > r:
                r = i + k
                c = i
        # p[i]为 ss 中回文半径 
        # p[j] - 1为原始串 s 回文长度
        # i = j * 2 + 1
        n1 = len(s)
        dp = [inf] * (n1 + 1)
        dp[0] = -1
        for i in range(1,n1 + 1):
            for j in range(i,n1 + 1):
                mid = i + j - 1 # 回文中心
                # 判断s[i:j]是否是回文
                if  p[mid] - 1 >= j - i + 1: # 中心的回文串长度覆盖s[i:j]
                    dp[j] = min(dp[j],dp[i - 1] + 1)

        return dp[-1]

相关文章:

  • 【领域】百度OCR识别
  • 请AI帮我们进行JAVA ORM 框架的选型, Hibernate, Mybatis, Bee,如何选择
  • 类和对象进一步了解c++
  • ​SMPP 协议在短信网关中的应用与迁移指南​附上文档地址(另外有个包内的方法,我使用的版本是又问题的,文章已经附上解决方式)
  • cellphonedb v5受配体多组比较气泡图(原创函数)
  • Ubuntu系统中测试硬盘速度
  • java作业
  • [转盘寿司]
  • ES批量查询
  • 网络分层 DNS CDN简单概念梳理
  • vcpkg 与 CMake 集成的步骤
  • 从零搭建微服务项目Pro(第1-3章——Quartz定时任务模块整合)
  • Perl 调用 DeepSeek API 脚本
  • 云原生监控篇——全链路可观测性与AIOps实战
  • 安装即是高级版!专业版软件,
  • Hadoop之01:HDFS分布式文件系统
  • Xshell及Xftp v8.0安装与使用-生信工具050
  • 【AI学习从零至壹】pytorch基础
  • Linux安装Apache2.4.54操作步骤
  • 前端js搭建(搭建后包含cookie,弹窗,禁用f12)
  • 天津网站建设制作品牌公司/seo点击工具帮你火21星热情
  • 芜湖网站优化公司/小说推广平台有哪些
  • 旅游网站设计的目的/智能营销系统
  • 医院网站建设策划/抖音指数查询
  • 电影网站域名/制作一个网站的基本步骤
  • 网站建设公司做前端/搜狗推广登录