LeetCode第132题_分割回文串II

news2025/4/12 14:33:46

LeetCode 第132题:分割回文串 II

题目描述

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

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

难度

困难

题目链接

点击在LeetCode中查看题目

示例

示例 1:

输入:s = "aab"
输出:1
解释:只需一次分割就可将 s 分割成 ["aa","b"] 这样两个回文子串。

示例 2:

输入:s = "a"
输出:0

示例 3:

输入:s = "ab"
输出:1

提示

  • 1 <= s.length <= 2000
  • s 仅由小写英文字母组成

解题思路

方法一:动态规划

这道题是"分割回文串"的进阶版,要求找到最少的分割次数,使得分割后的每个子串都是回文串。我们可以使用动态规划来解决这个问题。

关键点:

  • 使用动态规划预处理判断子串是否为回文串
  • 使用动态规划计算最少分割次数

具体步骤:

  1. 预处理判断子串是否为回文串
    • 定义isPalindrome[i][j]表示s[i…j]是否为回文串
    • 状态转移方程:isPalindrome[i][j] = (s[i] == s[j]) && (j - i <= 1 || isPalindrome[i+1][j-1])
  2. 计算最少分割次数
    • 定义dp[i]表示s[0…i]的最少分割次数
    • 初始化dp[i] = i(最坏情况下,每个字符都是一个回文串,需要i次分割)
    • 状态转移方程:
      • 如果s[0…i]是回文串,则dp[i] = 0(不需要分割)
      • 否则,遍历j从0到i-1,如果s[j+1…i]是回文串,则dp[i] = min(dp[i], dp[j] + 1)
  3. 返回dp[n-1],其中n是字符串的长度

时间复杂度:O(n2),其中n是字符串的长度。需要O(n2)的时间预处理回文串,以及O(n^2)的时间计算最少分割次数。
空间复杂度:O(n2),需要O(n2)的空间存储isPalindrome数组,以及O(n)的空间存储dp数组。

方法二:优化的动态规划

我们可以对方法一进行优化,减少空间复杂度。

关键点:

  • 使用中心扩展法判断回文串,避免使用O(n^2)的空间
  • 使用动态规划计算最少分割次数

具体步骤:

  1. 定义dp[i]表示s[0…i]的最少分割次数
  2. 初始化dp[i] = i(最坏情况下,每个字符都是一个回文串,需要i次分割)
  3. 对于每个位置i,以i为中心向两边扩展,找到所有以i为中心的回文串
    • 对于奇数长度的回文串,从i向两边扩展
    • 对于偶数长度的回文串,从i和i+1向两边扩展
  4. 对于每个找到的回文串s[j…i],更新dp[i] = min(dp[i], dp[j-1] + 1)
  5. 如果s[0…i]是回文串,则dp[i] = 0
  6. 返回dp[n-1]

时间复杂度:O(n^2),其中n是字符串的长度。
空间复杂度:O(n),只需要O(n)的空间存储dp数组。

图解思路

动态规划过程分析表

以示例1为例:s = “aab”

预处理回文串
isPalindrome[i][j]j=0j=1j=2
i=0truetruefalse
i=1-truefalse
i=2--true
计算最少分割次数
is[0…i]dp[i]初始值计算过程最终dp[i]说明
0“a”0s[0…0]是回文串,dp[0] = 00单个字符是回文串,不需要分割
1“aa”1s[0…1]是回文串,dp[1] = 00"aa"是回文串,不需要分割
2“aab”2s[0…2]不是回文串
s[1…2]不是回文串,dp[2] = min(dp[2], dp[0] + 1) = min(2, 0 + 1) = 1
s[2…2]是回文串,dp[2] = min(dp[2], dp[1] + 1) = min(1, 0 + 1) = 1
1"aab"需要分割一次

中心扩展法分析表

中心位置扩展类型找到的回文串更新dp[i]说明
0奇数长度“a”dp[0] = 0单个字符是回文串
0偶数长度“aa”dp[1] = 0"aa"是回文串
1奇数长度“a”dp[1] = min(dp[1], dp[0] + 1) = 0dp[1]已经是0,不更新
1偶数长度“ab”-"ab"不是回文串,不更新
2奇数长度“b”dp[2] = min(dp[2], dp[1] + 1) = min(2, 0 + 1) = 1更新dp[2] = 1

代码实现

C# 实现

public class Solution {
    public int MinCut(string s) {
        int n = s.Length;
        
        // 预处理回文串
        bool[,] isPalindrome = new bool[n, n];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j <= i; j++) {
                if (s[j] == s[i] && (i - j <= 1 || isPalindrome[j + 1, i - 1])) {
                    isPalindrome[j, i] = true;
                }
            }
        }
        
        // 计算最少分割次数
        int[] dp = new int[n];
        for (int i = 0; i < n; i++) {
            dp[i] = i; // 最坏情况下,需要i次分割
            
            if (isPalindrome[0, i]) {
                dp[i] = 0; // 如果s[0...i]是回文串,不需要分割
                continue;
            }
            
            for (int j = 0; j < i; j++) {
                if (isPalindrome[j + 1, i]) {
                    dp[i] = Math.Min(dp[i], dp[j] + 1);
                }
            }
        }
        
        return dp[n - 1];
    }
}

Python 实现

class Solution:
    def minCut(self, s: str) -> int:
        n = len(s)
        
        # 预处理回文串
        is_palindrome = [[False] * n for _ in range(n)]
        for i in range(n):
            for j in range(i + 1):
                if s[j] == s[i] and (i - j <= 1 or is_palindrome[j + 1][i - 1]):
                    is_palindrome[j][i] = True
        
        # 计算最少分割次数
        dp = list(range(n))  # 初始化dp[i] = i
        for i in range(n):
            if is_palindrome[0][i]:
                dp[i] = 0  # 如果s[0...i]是回文串,不需要分割
                continue
            
            for j in range(i):
                if is_palindrome[j + 1][i]:
                    dp[i] = min(dp[i], dp[j] + 1)
        
        return dp[n - 1]

C++ 实现

class Solution {
public:
    int minCut(string s) {
        int n = s.length();
        
        // 预处理回文串
        vector<vector<bool>> isPalindrome(n, vector<bool>(n, false));
        for (int i = 0; i < n; i++) {
            for (int j = 0; j <= i; j++) {
                if (s[j] == s[i] && (i - j <= 1 || isPalindrome[j + 1][i - 1])) {
                    isPalindrome[j][i] = true;
                }
            }
        }
        
        // 计算最少分割次数
        vector<int> dp(n);
        for (int i = 0; i < n; i++) {
            dp[i] = i; // 最坏情况下,需要i次分割
            
            if (isPalindrome[0][i]) {
                dp[i] = 0; // 如果s[0...i]是回文串,不需要分割
                continue;
            }
            
            for (int j = 0; j < i; j++) {
                if (isPalindrome[j + 1][i]) {
                    dp[i] = min(dp[i], dp[j] + 1);
                }
            }
        }
        
        return dp[n - 1];
    }
};

执行结果

C# 实现

  • 执行用时:92 ms
  • 内存消耗:39.8 MB

Python 实现

  • 执行用时:1024 ms
  • 内存消耗:31.2 MB

C++ 实现

  • 执行用时:56 ms
  • 内存消耗:8.7 MB

性能对比

语言执行用时内存消耗特点
C#92 ms39.8 MB执行速度适中,内存消耗较高
Python1024 ms31.2 MB执行速度较慢,内存消耗适中
C++56 ms8.7 MB执行速度最快,内存消耗最低

代码亮点

  1. 🎯 使用动态规划预处理回文串,避免重复计算
  2. 💡 巧妙利用dp数组存储最少分割次数,状态转移清晰
  3. 🔍 优化判断条件,当s[0…i]是回文串时直接设置dp[i] = 0
  4. 🎨 代码结构清晰,逻辑简单易懂

常见错误分析

  1. 🚫 预处理回文串的状态转移方程错误,导致判断回文串不正确
  2. 🚫 初始化dp数组不正确,影响最终结果
  3. 🚫 没有考虑s[0…i]是回文串的特殊情况,导致计算错误
  4. 🚫 遍历顺序错误,导致状态转移不正确

解法对比

解法时间复杂度空间复杂度优点缺点
动态规划(预处理回文串)O(n^2)O(n^2)实现简单,思路清晰空间复杂度较高
优化的动态规划(中心扩展法)O(n^2)O(n)空间复杂度较低实现稍复杂
回溯(暴力枚举)O(2^n)O(n)思路直观时间复杂度高,会超时

相关题目

  • LeetCode 131. 分割回文串 - 中等
  • LeetCode 5. 最长回文子串 - 中等
  • LeetCode 647. 回文子串 - 中等
  • LeetCode 1745. 回文串分割 IV - 困难
  • LeetCode 1278. 分割回文串 III - 困难

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2329995.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LabVIEW 在故障诊断中的算法

在故障诊断领域&#xff0c;LabVIEW 凭借其强大的图形化编程能力、丰富多样的工具包以及卓越的功能性能&#xff0c;成为工程师们进行故障诊断系统开发的得力助手。通过运用各种算法&#xff0c;能够对采集到的信号进行全面、深入的分析处理&#xff0c;从而准确地诊断出系统中…

springboot 启动方式 装配流程 自定义starter 文件加载顺序 常见设计模式

目录 springboot介绍 核心特性 快速搭建 Spring Boot 项目 方式一&#xff1a;使用 Spring Initializr 方式二&#xff1a;使用 IDE 插件 示例代码 1. 创建项目并添加依赖 2. 创建主应用类 3. 创建控制器类 4. 运行应用程序 配置文件 部署和监控 部署 监控 与其…

Android学习之Material Components

以下是 Material Design 提供的核心控件列表&#xff08;基于最新 Material Components for Android 库&#xff09;&#xff0c;按功能分类整理&#xff1a; 1. 基础按钮类 控件名称类名说明MaterialButtoncom.google.android.material.button.MaterialButton遵循 Material 规…

sentinel新手入门安装和限流,热点的使用

1 sentinel入门 1.1下载sentinel控制台 &#x1f517;sentinel管理后台官方下载地址 下载完毕以后就会得到一个jar包 1.2启动sentinel 将jar包放到任意非中文目录&#xff0c;执行命令&#xff1a; java -jar 名字.jar如果要修改Sentinel的默认端口、账户、密码&#xff…

Ubuntu 22 Linux上部署DeepSeek R1保姆式操作详解(Xinference方式)

一、安装步骤 1.基础环境安装 安装显卡驱动、cuda&#xff0c;根据自己硬件情况查找相应编号&#xff0c;本篇不介绍这部分内容&#xff0c;只给出参考指令&#xff0c;详情请读者自行查阅互联网其它参考资料。 sudo apt install nvidia-utils-565-server sudo apt install…

CTF类题目复现总结-hashcat 1

一、题目地址 https://buuoj.cn/challenges#hashcat二、复现步骤 1、下载附件&#xff0c;解压得到What kind of document is this_文件&#xff1b; 2、用010 Editor打开What kind of document is this_文件&#xff0c;发现是office文件&#xff1b; 3、将后缀名改为ppt时…

4月5日作业

需求&#xff1a; 1.按照图示的VLAN及IP地址需求&#xff0c;完成相关配置 2.要求SW 1为VLAN 2/3的主根及主网关 SW2为VLAN 20/30的主根及主网关&#xff0c;SW1和 SW2互为备份 3.可以使用super vlan 4.上层通过静态路由协议完成数据通信过程 5.AR1为企业出口路由器…

Bert论文解析

文章目录 BERT&#xff1a;用于语言理解的深度双向转换器的预训练一、摘要三、BERT介绍BERT及其详细实现答疑&#xff1a;为什么没有标注的数据可以用来预训练模型&#xff1f;1. 掩码语言模型&#xff08;Masked Language Model, MLM&#xff09;2. 下一句预测&#xff08;Nex…

无招回归阿里

这两天&#xff0c;无招回归阿里的新闻被刷屏了。无招创业成立的两氢一氧公司无招的股份也被阿里收购&#xff0c;无招以这种姿态回归阿里&#xff0c;并且出任钉钉的 CEO。有人说&#xff0c;这是对 5 年前“云钉一体”战略的纠偏。现在确实从云优先到 AI 优先&#xff0c;但云…

初探:简道云平台架构及原理

一、系统架构概述 简道云作为一款低代码开发平台&#xff0c;其架构设计以模块化和云端协同为核心&#xff0c;主要分为以下层次&#xff1a; 1. 前端层 可视化界面&#xff1a;基于Web的拖拽式表单设计器&#xff0c;支持动态渲染&#xff08;React/Vue框架&#xff09;。多…

Redis(笔记)

简介&#xff1a; 常用数据类型: 常用操作命令&#xff1a; Redis的Java客户端&#xff1a; 操作字符串类型的数据&#xff1a; 操作Hash类型的数据&#xff1a; 操作列表类型的数据&#xff1a; 操作集合类型的数据&#xff1a; 操作有序集合类型数据&#xff1a; 通用命令…

bootloader+APP中,有些APP引脚无法正常使用?

问&#xff1a;bootloaderAPP程序中&#xff0c;为什么有些APP引脚无法正常使用&#xff1f;无法设置高低电平 主控芯片GD32F415&#xff0c;参考案例bootloader中的引脚使用&#xff1a; 参考案例APP程序的引脚使用&#xff1a; 以及个人使用的无线模组&#xff0c;高电平使能…

高并发内存池:原理、设计与多线程性能优化实践

高并发内存池是一种专门为多线程环境设计的内存管理机制&#xff0c;其核心目标是通过优化内存分配和释放过程&#xff0c;解决传统内存分配器&#xff08;如malloc/free&#xff09;在高并发场景下的性能瓶颈&#xff0c;显著提升多线程程序的内存访问效率。 目录 一、核心设计…

基于内容的课程推荐网站的设计与实现00(SSM+htmlL)

基于内容的课程推荐网站的设计与实现(SSMhtml) 该系统是一个基于内容的课程推荐网站&#xff0c;旨在为用户提供个性化的课程推荐。系统包含多个模块&#xff0c;如教学视频、教学案例、课程信息、系统公告、个人中心和后台管理。用户可以通过首页访问不同的课程分类&#xff…

生活电子常识--删除谷歌浏览器搜索记录

前言 谷歌浏览器会记录浏览器历史搜索,如果不希望看到越来越多的搜索记录,可以如下设置 解决 设置-隐私-自动填充表单 这个和浏览器记录的密码没有关系,可以放心删除

学习threejs,使用Texture纹理贴图,测试repeat重复纹理贴图

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️Texture 纹理贴图1.1.1 ☘️…

蓝桥杯基础算法-字符串与集合

对集合的考察集中在集合的特性和功能。 set-唯一性 list-有序性 集合元素的个数 思路分析&#xff1a;set的唯一性&#xff0c;取出重复的子串 eg&#xff1a; 下标0截取的范围&#xff1a;【0&#xff0c;最大下标】 下标1截取的范围&#xff1a;【1&#xff0c;最大下标…

animals_classification动物分类

数据获取 深度学习训练中第一个是获取数据集&#xff0c;数据集的质量很重要&#xff0c;我们这里做的是动物分类&#xff0c;大致会选择几个动物&#xff0c;来做一个简单的多分类问题&#xff0c;数据获取的方法&#xff0c;鼠鼠我这里选择使用爬虫的方式来对数据进行爬取&a…

解决Oracle PL/SQL中“表或视图不存在“错误的完整指南

解决Oracle PL/SQL中"表或视图不存在"错误的完整指南 前言问题概述根本原因分析一、 编译时与运行时验证差异二、权限问题三、 Schema命名问题 实际案例演示案例1&#xff1a;动态分表查询案例2&#xff1a;权限不足的场景 实用排查步骤排查流程图最佳实践建议解决方…

SSH远程连接服务器(cursor)

安装Remote-SSH插件 Cursor是基于VSCode的&#xff0c;因此支持VSCode的Remote-SSH功能。打开Cursor&#xff0c;进入扩展市场&#xff08;左侧活动栏的“Extensions”图标&#xff09;。搜索“Remote - SSH”插件并安装&#xff08;由Microsoft提供&#xff09;。 配置SSH 在…