LeetCode第132题_分割回文串II
LeetCode 第132题:分割回文串 II
题目描述
给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是回文。
返回符合要求的 最少分割次数 。
难度
困难
题目链接
点击在LeetCode中查看题目
示例
示例 1:
输入:s = "aab"
输出:1
解释:只需一次分割就可将 s 分割成 ["aa","b"] 这样两个回文子串。
示例 2:
输入:s = "a"
输出:0
示例 3:
输入:s = "ab"
输出:1
提示
1 <= s.length <= 2000s仅由小写英文字母组成
解题思路
方法一:动态规划
这道题是"分割回文串"的进阶版,要求找到最少的分割次数,使得分割后的每个子串都是回文串。我们可以使用动态规划来解决这个问题。
关键点:
- 使用动态规划预处理判断子串是否为回文串
- 使用动态规划计算最少分割次数
具体步骤:
- 预处理判断子串是否为回文串
- 定义isPalindrome[i][j]表示s[i…j]是否为回文串
- 状态转移方程:isPalindrome[i][j] = (s[i] == s[j]) && (j - i <= 1 || isPalindrome[i+1][j-1])
- 计算最少分割次数
- 定义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)
- 返回dp[n-1],其中n是字符串的长度
时间复杂度:O(n2),其中n是字符串的长度。需要O(n2)的时间预处理回文串,以及O(n^2)的时间计算最少分割次数。
空间复杂度:O(n2),需要O(n2)的空间存储isPalindrome数组,以及O(n)的空间存储dp数组。
方法二:优化的动态规划
我们可以对方法一进行优化,减少空间复杂度。
关键点:
- 使用中心扩展法判断回文串,避免使用O(n^2)的空间
- 使用动态规划计算最少分割次数
具体步骤:
- 定义dp[i]表示s[0…i]的最少分割次数
- 初始化dp[i] = i(最坏情况下,每个字符都是一个回文串,需要i次分割)
- 对于每个位置i,以i为中心向两边扩展,找到所有以i为中心的回文串
- 对于奇数长度的回文串,从i向两边扩展
- 对于偶数长度的回文串,从i和i+1向两边扩展
- 对于每个找到的回文串s[j…i],更新dp[i] = min(dp[i], dp[j-1] + 1)
- 如果s[0…i]是回文串,则dp[i] = 0
- 返回dp[n-1]
时间复杂度:O(n^2),其中n是字符串的长度。
空间复杂度:O(n),只需要O(n)的空间存储dp数组。
图解思路
动态规划过程分析表
以示例1为例:s = “aab”
预处理回文串
| isPalindrome[i][j] | j=0 | j=1 | j=2 |
|---|---|---|---|
| i=0 | true | true | false |
| i=1 | - | true | false |
| i=2 | - | - | true |
计算最少分割次数
| i | s[0…i] | dp[i]初始值 | 计算过程 | 最终dp[i] | 说明 |
|---|---|---|---|---|---|
| 0 | “a” | 0 | s[0…0]是回文串,dp[0] = 0 | 0 | 单个字符是回文串,不需要分割 |
| 1 | “aa” | 1 | s[0…1]是回文串,dp[1] = 0 | 0 | "aa"是回文串,不需要分割 |
| 2 | “aab” | 2 | s[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) = 0 | dp[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] = ifor i in range(n):if is_palindrome[0][i]:dp[i] = 0 # 如果s[0...i]是回文串,不需要分割continuefor 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 ms | 39.8 MB | 执行速度适中,内存消耗较高 |
| Python | 1024 ms | 31.2 MB | 执行速度较慢,内存消耗适中 |
| C++ | 56 ms | 8.7 MB | 执行速度最快,内存消耗最低 |
代码亮点
- 🎯 使用动态规划预处理回文串,避免重复计算
- 💡 巧妙利用dp数组存储最少分割次数,状态转移清晰
- 🔍 优化判断条件,当s[0…i]是回文串时直接设置dp[i] = 0
- 🎨 代码结构清晰,逻辑简单易懂
常见错误分析
- 🚫 预处理回文串的状态转移方程错误,导致判断回文串不正确
- 🚫 初始化dp数组不正确,影响最终结果
- 🚫 没有考虑s[0…i]是回文串的特殊情况,导致计算错误
- 🚫 遍历顺序错误,导致状态转移不正确
解法对比
| 解法 | 时间复杂度 | 空间复杂度 | 优点 | 缺点 |
|---|---|---|---|---|
| 动态规划(预处理回文串) | 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 - 困难
相关文章:
LeetCode第132题_分割回文串II
LeetCode 第132题:分割回文串 II 题目描述 给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是回文。 返回符合要求的 最少分割次数 。 难度 困难 题目链接 点击在LeetCode中查看题目 示例 示例 1: 输入…...
LabVIEW 在故障诊断中的算法
在故障诊断领域,LabVIEW 凭借其强大的图形化编程能力、丰富多样的工具包以及卓越的功能性能,成为工程师们进行故障诊断系统开发的得力助手。通过运用各种算法,能够对采集到的信号进行全面、深入的分析处理,从而准确地诊断出系统中…...
SQL DB 数据类型
SQL DB 数据类型 引言 在数据库管理系统中,数据类型是定义和存储数据的方式。SQL(结构化查询语言)数据库中的数据类型决定了数据的存储格式、大小、取值范围以及如何处理数据。合理选择和使用数据类型对于确保数据库性能、数据完整性和应用程序的准确性至关重要。 SQL 数…...
Qt音频输出:QAudioOutput详解与示例
1. 简介 QAudioOutput是Qt多媒体框架中的一个关键类,它提供了将PCM(脉冲编码调制)原始音频数据发送到音频输出设备的接口。作为Qt多媒体组件的一部分,QAudioOutput允许开发者在应用程序中实现音频播放功能,支持多种音…...
springboot 启动方式 装配流程 自定义starter 文件加载顺序 常见设计模式
目录 springboot介绍 核心特性 快速搭建 Spring Boot 项目 方式一:使用 Spring Initializr 方式二:使用 IDE 插件 示例代码 1. 创建项目并添加依赖 2. 创建主应用类 3. 创建控制器类 4. 运行应用程序 配置文件 部署和监控 部署 监控 与其…...
Android学习之Material Components
以下是 Material Design 提供的核心控件列表(基于最新 Material Components for Android 库),按功能分类整理: 1. 基础按钮类 控件名称类名说明MaterialButtoncom.google.android.material.button.MaterialButton遵循 Material 规…...
sentinel新手入门安装和限流,热点的使用
1 sentinel入门 1.1下载sentinel控制台 🔗sentinel管理后台官方下载地址 下载完毕以后就会得到一个jar包 1.2启动sentinel 将jar包放到任意非中文目录,执行命令: java -jar 名字.jar如果要修改Sentinel的默认端口、账户、密码ÿ…...
Ubuntu 22 Linux上部署DeepSeek R1保姆式操作详解(Xinference方式)
一、安装步骤 1.基础环境安装 安装显卡驱动、cuda,根据自己硬件情况查找相应编号,本篇不介绍这部分内容,只给出参考指令,详情请读者自行查阅互联网其它参考资料。 sudo apt install nvidia-utils-565-server sudo apt install…...
ANTLR 实战_从零开始构建自定义语言解析器
1. 引言 1.1 什么是 ANTLR ANTLR(Another Tool for Language Recognition)是一个强大的解析器生成器,用于构建语言解析器、编译器和解释器。 1.2 ANTLR 的历史与发展 ANTLR 由 Terence Parr 创建,最初发布于 1995 年。经过多次版本更新,ANTLR 已成为构建解析器的首选工…...
CTF类题目复现总结-hashcat 1
一、题目地址 https://buuoj.cn/challenges#hashcat二、复现步骤 1、下载附件,解压得到What kind of document is this_文件; 2、用010 Editor打开What kind of document is this_文件,发现是office文件; 3、将后缀名改为ppt时…...
4月5日作业
需求: 1.按照图示的VLAN及IP地址需求,完成相关配置 2.要求SW 1为VLAN 2/3的主根及主网关 SW2为VLAN 20/30的主根及主网关,SW1和 SW2互为备份 3.可以使用super vlan 4.上层通过静态路由协议完成数据通信过程 5.AR1为企业出口路由器…...
Bert论文解析
文章目录 BERT:用于语言理解的深度双向转换器的预训练一、摘要三、BERT介绍BERT及其详细实现答疑:为什么没有标注的数据可以用来预训练模型?1. 掩码语言模型(Masked Language Model, MLM)2. 下一句预测(Nex…...
无招回归阿里
这两天,无招回归阿里的新闻被刷屏了。无招创业成立的两氢一氧公司无招的股份也被阿里收购,无招以这种姿态回归阿里,并且出任钉钉的 CEO。有人说,这是对 5 年前“云钉一体”战略的纠偏。现在确实从云优先到 AI 优先,但云…...
初探:简道云平台架构及原理
一、系统架构概述 简道云作为一款低代码开发平台,其架构设计以模块化和云端协同为核心,主要分为以下层次: 1. 前端层 可视化界面:基于Web的拖拽式表单设计器,支持动态渲染(React/Vue框架)。多…...
LeetCode 热题 100 堆
215. 数组中的第K个最大元素 给定整数数组 nums 和整数 k,请返回数组中第 **k** 个最大的元素。 请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。 你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。 示例 …...
面试常被问道OSPF的问题
面试中经常会涉及到OSPF相关的问题,作为网络工程师,我们对OSPF的了解可不能仅停留在“我知道它是路由协议”这么表面。 想面试官满意,拿到Offer,必须能回答得出细节,深度挖掘它的工作原理、配置技巧、以及应用场景。 …...
Redis(笔记)
简介: 常用数据类型: 常用操作命令: Redis的Java客户端: 操作字符串类型的数据: 操作Hash类型的数据: 操作列表类型的数据: 操作集合类型的数据: 操作有序集合类型数据: 通用命令…...
bootloader+APP中,有些APP引脚无法正常使用?
问:bootloaderAPP程序中,为什么有些APP引脚无法正常使用?无法设置高低电平 主控芯片GD32F415,参考案例bootloader中的引脚使用: 参考案例APP程序的引脚使用: 以及个人使用的无线模组,高电平使能…...
高并发内存池:原理、设计与多线程性能优化实践
高并发内存池是一种专门为多线程环境设计的内存管理机制,其核心目标是通过优化内存分配和释放过程,解决传统内存分配器(如malloc/free)在高并发场景下的性能瓶颈,显著提升多线程程序的内存访问效率。 目录 一、核心设计…...
基于内容的课程推荐网站的设计与实现00(SSM+htmlL)
基于内容的课程推荐网站的设计与实现(SSMhtml) 该系统是一个基于内容的课程推荐网站,旨在为用户提供个性化的课程推荐。系统包含多个模块,如教学视频、教学案例、课程信息、系统公告、个人中心和后台管理。用户可以通过首页访问不同的课程分类ÿ…...
生活电子常识--删除谷歌浏览器搜索记录
前言 谷歌浏览器会记录浏览器历史搜索,如果不希望看到越来越多的搜索记录,可以如下设置 解决 设置-隐私-自动填充表单 这个和浏览器记录的密码没有关系,可以放心删除...
学习threejs,使用Texture纹理贴图,测试repeat重复纹理贴图
👨⚕️ 主页: gis分享者 👨⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨⚕️ 收录于专栏:threejs gis工程师 文章目录 一、🍀前言1.1 ☘️Texture 纹理贴图1.1.1 ☘️…...
Git常用问题收集
gitignore 忽略文件夹 不生效 有时候我们接手别人的项目时,发现有的忽略不对想要修改,但发现修改忽略.gitignore后无效。原因是如果某些文件已经被纳入版本管理在.gitignore中忽略路径是不起作用的,这时候需要先清除本地缓存,然后…...
蓝桥杯基础算法-字符串与集合
对集合的考察集中在集合的特性和功能。 set-唯一性 list-有序性 集合元素的个数 思路分析:set的唯一性,取出重复的子串 eg: 下标0截取的范围:【0,最大下标】 下标1截取的范围:【1,最大下标…...
animals_classification动物分类
数据获取 深度学习训练中第一个是获取数据集,数据集的质量很重要,我们这里做的是动物分类,大致会选择几个动物,来做一个简单的多分类问题,数据获取的方法,鼠鼠我这里选择使用爬虫的方式来对数据进行爬取&a…...
对解释器模式的理解
对解释器模式的理解 一、场景1、题目【[来源](https://kamacoder.com/problempage.php?pid1096)】1.1 题目描述1.2 输入描述1.3 输出描述1.4 输入示例1.5 输出示例 二、不采用解释器模式1、代码2、“缺点” 三、采用解释器模式1、代码2、“优点” 四、思考1、解释器模式的意义…...
解决Oracle PL/SQL中“表或视图不存在“错误的完整指南
解决Oracle PL/SQL中"表或视图不存在"错误的完整指南 前言问题概述根本原因分析一、 编译时与运行时验证差异二、权限问题三、 Schema命名问题 实际案例演示案例1:动态分表查询案例2:权限不足的场景 实用排查步骤排查流程图最佳实践建议解决方…...
【Kubernetes】StorageClass 的作用是什么?如何实现动态存储供应?
StorageClass 使得用户能够根据不同的存储需求动态地申请和管理存储资源。 StorageClass 定义了如何创建存储资源,并指定了存储供应的配置,例如存储类型、质量、访问模式等。为动态存储供应提供了基础,使得 Kubernetes 可以在用户创建 PVC 时…...
linux如何查看当前系统的资源占用情况
在 Linux 系统中,有多个命令可以查看当前系统的资源占用情况。以下是一些常用的命令及其说明: 1. 查看内存使用情况:free free -h-h 参数表示以人类可读的格式显示(如 MB, GB)。输出示例: to…...
Arduino示例代码讲解:Row-Column Scanning an 8x8 LED matrix with X-Y input LED矩阵
Arduino示例代码讲解:Row-Column Scanning an 8x8 LED matrix with X-Y input LED矩阵 Row-Column Scanning an 8x8 LED matrix with X-Y input LED矩阵功能概述硬件部分:软件部分:代码逐行解释定义常量定义变量`setup()` 函数`loop()` 函数`readSensors()` 函数`refreshScr…...
