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

DP:回文串模型

一、回文子串

. - 力扣(LeetCode)

 该题有3种解法

(1)中心扩展算法(在字符串章节有介绍)时间复杂度O(N^2),空间复杂度O(1)

(2)马丁车算法(专门用来解决回文串问题,但是适用返回太窄)时间复杂度O(N),空间复杂度O(N)

(3)动态规划(可以将所有回文信息都保存在dp表中)时间复杂度O(N^2),空间复杂度O(N^2)

这边重点介绍动态规划的做法。

算法原理:

1、状态表示(经验+题目要求)

dp[i][j]表示s字符串[i,j]的子串是否是回文串(i<=j)只需处理右上区即可

 2、状态转移方程

dp[i][j]:  

(1)s[i]!=s[j]——>false

(2)s[i]==s[j]——>

      i==j  true 

      i+1==j   true

      dp[i+1][j-1]

3、初始化

无需初始化

4、填表顺序

dp[i][j]会用到dp[i+1][j-1],所以必须要从下往上填 , 左右顺序不重要

5、返回值

dp表中true的个数

class Solution {
public:int countSubstrings(string s) {//动态规划的做法int ret=0;//s[i]==s[j]  1、i==j  2、i+1==j  3、dp[i+1][j-1]?int n=s.size();vector<vector<bool>> dp(n,vector<bool>(n));//只要右上半区 for(int i=n-1;i>=0;--i)  //要从下往上  左右无所谓,因为用不到for(int j=i;j<n;++j) //只要右上半区if(s[i]==s[j]) ret+=dp[i][j]=i+1<j?dp[i+1][j-1]:true;return ret;}
};

 二、最长回文子串

. - 力扣(LeetCode)

算法原理:

1、状态表示(经验+题目要求)

dp[i][j]表示s字符串[i,j]的子串是否是回文串(i<=j)只需处理右上区即可

 2、状态转移方程

dp[i][j]:  

(1)s[i]!=s[j]——>false

(2)s[i]==s[j]——>

      i==j  true 

      i+1==j   true

      dp[i+1][j-1]

3、初始化

无需初始化

4、填表顺序

dp[i][j]会用到dp[i+1][j-1],所以必须要从下往上填 , 左右顺序不重要

5、返回值

dp表中为true以及长度最大的子串的起始位置和长度

class Solution {
public:string longestPalindrome(string s) {//动态规划的思想int begin=0,len=1;//帮助我们返回结果int n=s.size();vector<vector<bool>> dp(n,vector<bool>(n));for(int i=n-1;i>=0;--i)for(int j=i;j<n;++j) //右上角部分{if(s[i]==s[j]) {dp[i][j]=i+1<j?dp[i+1][j-1]:true;if(dp[i][j]&&len<j-i+1) {begin=i;len=j-i+1;}}  }return s.substr(begin,len);}
};

三、分割回文子串I

. - 力扣(LeetCode)

解法1:动归预处理+回溯

class Solution {
public://动归预处理+回溯vector<vector<bool>> dp;//dp预处理vector<vector<string>> ret;//记录返回的结果vector<string> path;//记录路径的结果int n;vector<vector<string>> partition(string s) {//dp预处理n=s.size();dp.resize(n,vector<bool>(n));for(int i=n-1;i>=0;--i)for(int j=i;j<n;++j)if(s[i]==s[j])  dp[i][j]=i+1<j?dp[i+1][j-1]:true;//将dp数组交给dfs去处理dfs(s,0);return ret;}void dfs(string&s,int i){if(i==n) {ret.push_back(path);return;}for(int j=i;j<n;++j)if(dp[i][j]){path.emplace_back(s.substr(i,j-i+1));dfs(s,j+1);path.pop_back();}}
};

 解法2:回溯+记忆化搜索

class Solution {
public:
//回溯+记忆化搜索vector<vector<int>> f;//记忆化数组  0表示未搜索,1表示回文,-1表示不回文vector<vector<string>> ret;//记录返回的结果vector<string> path;//记录路径的结果int n;vector<vector<string>> partition(string s) {n=s.size();f.resize(n,vector<int>(n));//交给dfs帮助我们解决dfs(s,0);return ret;}void dfs(const string&s,int i){if(i==n) {ret.emplace_back(path);return;}for(int j=i;j<n;++j)if(ispal(s,i,j)){path.emplace_back(s.substr(i,j-i+1));dfs(s,j+1);path.pop_back();}}bool ispal(const string&s,int i,int j) //判断i->j是否回文{//先看看备忘录if(f[i][j]) return f[i][j];if(s[i]!=s[j]) return f[i][j]=false;else return f[i][j]=i+1<j?ispal(s,i+1,j-1):true;}
};

四、分割回文子串II

. - 力扣(LeetCode)

算法原理:

1、状态表示(经验+题目要求)

dp[i]表示s字符串[0,i]区间上的最长子串的最小分割次数

 2、状态转移方程

dp[i]:  

(1)0-i回文——>0

(2)0-i不是回文——>j-i是否回文——>min(dp[i],dp[j-1]+1)

3、初始化

都初始化为整型最大值,否则最后dp表里都是0会影响结果

4、填表顺序

dp[i][j]会用到dp[i+1][j-1],所以必须要从下往上填 , 左右顺序不重要

5、返回值

dp[n-1]

class Solution {
public:int minCut(string s) {int n=s.size();vector<vector<bool>> ispal(n,vector<bool>(n));for(int i=n-1;i>=0;--i)for(int j=i;j<n;++j) //右上角部分if(s[i]==s[j])   ispal[i][j]=i+1<j?ispal[i+1][j-1]:true;//第二次枚举 尝试去分割 vector<int> dp(n,INT_MAX);//初始化为无穷大  for(int i=0;i<n;++i)//先看看左边的部分if(ispal[0][i]) dp[i]=0;elsefor(int j=1;j<=i;++j)//去看看左边 要怎么切割 左开右闭if(ispal[j][i]) dp[i]=min(dp[i],dp[j-1]+1);//j代表最后一个回文串的起始位置return dp[n-1];}
};

五、分割回文子串III(经典)

. - 力扣(LeetCode)

算法原理:

1、状态表示(经验+题目要求)

dp[i][j]表示对于字符串的前i个字符,将他分割成j个子串,所需修改的最少字符数

 2、状态转移方程

int cost(string&s,int l,int r) 表示从s的i-j位置,变成回文串所需要的最小修改次数

dp[i][j]:  

(1)j==1(没有分割)  cost(s,0,i-1)

(2)j>1——>min(dp[i][j],dp[m][j-1]+cost(s,m,i-1))

3、初始化

初始化成INT_MAX 确保不影响最终结果 dp[0][0]=0 确保不影响结果

4、填表顺序

上到下,左到右

5、返回值

dp[n][k]

class Solution {
public:int palindromePartition(string s, int k) {//dp[i][j]表示对于字符串的前i个字符,将他分割成j个子串,所需修改的最少字符数int n=s.size();vector<vector<int>> dp(n+1,vector<int>(k+1,INT_MAX));dp[0][0]=0;for(int i=1;i<=n;++i)for(int j=1;j<=min(k,i);++j)if(j==1) dp[i][j]=cost(s,0,i-1);else for(int m=j-1;m<i;++m) dp[i][j]=min(dp[i][j],dp[m][j-1]+cost(s,m,i-1));//找前面的状态 0->i  分成j个//dp0->m+ cost m->ireturn dp[n][k];//0->n  k}int cost(string&s,int l,int r){int ret=0;for(int i=l,j=r;i<j;++i,--j)if(s[i]!=s[j]) ++ret;//需要修改一个才能成为回文return ret;}
};

六、分割回文串IV

 . - 力扣(LeetCode)

算法原理:

1、状态表示(经验+题目要求)

dp[i][j]表示s字符串[i,j]的子串是否是回文串(i<=j)只需处理右上区即可

 2、状态转移方程

dp[i][j]:  

(1)s[i]!=s[j]——>false

(2)s[i]==s[j]——>

      i==j  true 

      i+1==j   true

      dp[i+1][j-1]

3、初始化

无需初始化

4、填表顺序

dp[i][j]会用到dp[i+1][j-1],所以必须要从下往上填 , 左右顺序不重要

5、返回值

第二次枚举,先固定第一个位置,然后固定第二个位置,看看由两个位置分割出来的三个区域是否都为true

class Solution {
public:bool checkPartitioning(string s) {//将结果存到dp表中int n=s.size();vector<vector<bool>> dp(n,vector<bool>(n));for(int i=n-1;i>=0;--i)for(int j=i;j<n;++j) //右上角部分if(s[i]==s[j])   dp[i][j]=i+1<j?dp[i+1][j-1]:true;//第二次枚举 先固定第一个,然后固定第二个,然后看看3个是不是都是true即可for(int i=1;i<n-1;++i)for(int j=i;j<n-1;++j)if(dp[0][i-1]&&dp[i][j]&&dp[j+1][n-1]) return true;return false;}
};

七、不重叠回文子字符串的最大数目

. - 力扣(LeetCode)

class Solution {
public:int maxPalindromes(string s, int k) {//dp[i]表示0->i中的不重叠回文子字符串的最大数目int n=s.size();vector<int> dp(n+1);//如果s[i]不在回文串中 dp[i+1]=dp[i]//如果s[r]在回文串中,采用中心扩展,l->r是回文子串,且r-l+1>=k 有dp[i]=max(dp[i],dp[l-1]+1)for(int i=0;i<n*2-1;++i){//两边到中间不适合判断长度,应该从中间到两边int l=i/2,r=l+i%2; //中心扩展判断是否回文dp[l+1]=max(dp[l],dp[l+1]);for(;l>=0&&r<n&&s[l]==s[r];--l,++r)if(r-l+1>=k){dp[r+1]=max(dp[r+1],dp[l]+1);break;}}return dp[n];}
};

八、最长回文子序列

. - 力扣(LeetCode)

class Solution {
public:int longestPalindromeSubseq(string s) {//子序列和子串的区别就是可以不连续int n=s.size();vector<vector<int>> dp(n,vector<int>(n));//只会用到右上半部分for(int i=n-1;i>=0;--i){//dp[i][j]表示i-j区间内所有子序列中,最长回文子序列的长度dp[i][i]=1;for(int j=i+1;j<n;++j)if(s[i]==s[j]) dp[i][j]=dp[i+1][j-1]+2; //i+1=j的情况可以不用考虑 //虽然会出现用不到的格子,但是里面是0所以不会影响计算结果else dp[i][j]=max(dp[i+1][j],dp[i][j-1]);}return dp[0][n-1];}
};

算法原理:

1、状态表示(经验+题目要求)

dp[i][j]表示s字符串[i,j]所有子序列中的最长子序列的长度

 2、状态转移方程

dp[i][j]:  

(1)s[i]!=s[j]——>max(dp[i,j-1],dp[i+1][j])

(2)s[i]==s[j]——>

      i==j  1

      i+1==j   2

      dp[i+1][j-1]+2

3、初始化

初始化为0  dp[i][i]=1

4、填表顺序

上到下,左到右

5、返回值

dp[0][n-1]

九、让字符串成为回文串的最小插入次数

. - 力扣(LeetCode)

算法原理:

1、状态表示(经验+题目要求)

dp[i][j]表示s字符串[i,j]子串,使他成为回文子串的最小插入次数

 2、状态转移方程

dp[i][j]:  

(1)s[i]!=s[j]——>min(dp[i,j-1],dp[i+1][j])+1

(2)s[i]==s[j]——>

      i==j  0

      i+1==j   0

      dp[i+1][j-1]

3、初始化

初始化为0 

4、填表顺序

下往上,左到右

5、返回值

dp[0][n-1]

class Solution {
public:int minInsertions(string s) {int n=s.size();vector<vector<int>> dp(n,vector<int>(n));for(int i=n-1;i>=0;--i)for(int j=i+1;j<n;++j)if(s[i]==s[j]) dp[i][j]=dp[i+1][j-1];else dp[i][j]=min(dp[i][j-1],dp[i+1][j])+1;return dp[0][n-1];}
};

 

相关文章:

DP:回文串模型

一、回文子串 . - 力扣&#xff08;LeetCode&#xff09; 该题有3种解法 &#xff08;1&#xff09;中心扩展算法&#xff08;在字符串章节有介绍&#xff09;时间复杂度O&#xff08;N^2&#xff09;,空间复杂度O&#xff08;1&#xff09; &#xff08;2&#xff09;马丁车…...

STM32CubeMX软件的安装以及配置

STM32CubeMX软件的配置过程可以详细分为以下几个步骤&#xff0c;以确保您能够顺利地使用该软件进行STM32微控制器的配置和代码生成&#xff1a; 1. 安装前准备 安装JAVA环境&#xff1a;由于STM32CubeMX软件是基于JAVA环境运行的&#xff0c;所以需要先安装Java Runtime Env…...

【适配鸿蒙next】Flutter 新一代混合栈管理框架

前言 据最新消息显示&#xff0c;华为今年下半年将全面转向其自主平台HarmonyOS&#xff0c;放弃Android系统。 报道中提到&#xff0c;下一版HarmonyOS预计将随华为即将推出的Mate 70旗舰系列一起发布。 据悉&#xff0c;HarmonyOS Next 已经扩展到4000个应用程序&#xff0c;…...

车载电子电气架构 --- 车载信息安全

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己,无利益不试图说服别人,是精神上的节…...

【数据结构(邓俊辉)学习笔记】图04——双连通域分解

文章目录 0. 概述1 关节点与双连通域2 蛮力算法3 可行算法4 实现5 示例6 复杂度 0. 概述 学习下双连通域分解&#xff0c;这里略微有一点点难&#xff0c;这个算是DFS算法的非常非常经典的应用&#xff0c;解决的问题也非常非常有用。 1 关节点与双连通域 连通性很好理解&am…...

UI学习(二)

UI学习&#xff08;二&#xff09; 文章目录 UI学习&#xff08;二&#xff09;布局子视图手动布局自动布局 导航控制器导航控制器基础导航控制器的切换导航栏工具栏 分栏控制器分栏控制器协议部分的内容UITableView基础部分相关的协议函数高级协议与单元格 多界面传值 布局子视…...

【嵌入式】波特率9600,发送8个字节需要多少时间,如何计算?

问题&#xff1a; 波特率9600&#xff0c;发送 01 03 00 00 00 04 44 09 (8字节) 需要多少时间&#xff0c;如何计算&#xff1f; 在计算发送数据的时间时&#xff0c;首先要考虑波特率以及每个字符的数据格式。对于波特率9600和标准的UART数据格式&#xff08;1个起始位&…...

jmeter -n -t 使用非GUI模式运行脚本说明

命令模式下执行jmx文件 jmeter -n -t fatie.jmx -l results\t4.jtl -e -o results\h1 表示以命令行模式运行当前目录下的脚本fatie.jmx,将结果存入当前目录下的results\t1.jtl,并且生成html格式的报告&#xff0c;写入文件夹results\h1。 说明&#xff1a;生成结果的文件夹r…...

网络流媒体协议——HLS协议

HTTP 实时流媒体&#xff08;HTTP Live Streaming&#xff0c;HLS&#xff09;协议是苹果公司提出的主要用于直播的流媒体协议。一个完整的基于HLS协议的流媒体直播系统由四部分组成&#xff0c;即音视频采集器、媒体服务器、媒体分发器和播放客户端。 媒体服务器 媒体服务器的…...

Linux服务器扩容及磁盘分区(LVM和非LVM)

Linux扩容及磁盘分区&#xff08;LVM和非LVM&#xff09; 本文主要介绍了阿里云服务器centos的扩容方法&#xff1a;非LVM分区扩容方法&#xff08;系统盘&#xff09;&#xff0c;以及磁盘改LVM并分区&#xff08;数据盘&#xff09;。主要是ext4文件系统及xfs磁盘scsi MBR分…...

支持向量机

支持向量机&#xff08;SVM&#xff09; 支持向量机&#xff08;Support Vector Machine, SVM&#xff09;是一种用于分类和回归任务的监督学习算法。SVM 的核心思想是找到一个最优的决策边界&#xff08;或称为超平面&#xff09;&#xff0c;以最大化不同类别之间的间隔。以…...

Kafka 架构

1 整体架构 1.1 Zookeeper Zookeeper 是一个分布式协调服务&#xff0c;用于管理 Kafka 的元数据。它负责维护 Kafka 集群的配置信息、Broker 列表和分区的 Leader 信息。 Zookeeper 确保了 Kafka 集群的高可用性和可靠性。 但 Zookeeper 已经成为 Kafka 性能瓶颈&#xff0c;…...

iOS 查看runtime源码的几种方法

目录 前言 查看runtime 源码方法 1.下载 Apple 官方提供的源代码 2.通过 GitHub 访问镜像 3.使用命令行工具查看 4.示例 前言 这篇博客主要介绍了查看iOS runtime源代码的方法。 查看runtime 源码方法 查看iOS runtime源码的方法包括以下几个步骤&#xff1a; 1.下载 A…...

底板外设倒灌到处理器分析

在嵌入式系统中&#xff0c;底板外设通常与处理器通过各种接口&#xff08;如UART、SPI、I2C、GPIO等&#xff09;进行连接。这些外设可能包括传感器、执行器、存储器、通信模块等。倒灌是指当外设向处理器提供的信号电平超出了处理器能够接受的范围&#xff0c;导致处理器无法…...

使用贝塞尔曲线实现一个iOS时间轴

UI效果 实现的思路 就是通过贝塞尔曲线画出时间轴的圆环的路径&#xff0c;然后 使用CAShaper来渲染UI&#xff0c;再通过 animation.beginTime [cilrclLayer convertTime:CACurrentMediaTime() fromLayer:nil] circleTimeOffset 来设置每个圆环的动画开始时间&#xff0c; …...

【深度学习】深度学习之巅:在 CentOS 7 上打造完美Python 3.10 与 PyTorch 2.3.0 环境

【深度学习】深度学习之巅&#xff1a;在 CentOS 7 上打造完美Python 3.10 与 PyTorch 2.3.0 环境 大家好 我是寸铁&#x1f44a; 总结了一篇【深度学习】深度学习之巅&#xff1a;在 CentOS 7 上打造完美Python 3.10 与 PyTorch 2.3.0 环境✨ 喜欢的小伙伴可以点点关注 &#…...

在docker容器中使用gdb调试python3.11的进程

gdb调试python进程的前提条件 安装python及python调试信息安装gdb工具安装python-gdb.py扩展 安装过程 我们使用docker来安装以上内容&#xff0c;Dockerfile文件内容如下&#xff1a; FROM docker.io/centos:7.4.1708# 安装依赖 RUN yum install -y -q epel-release &…...

堆排序要点和难点以及具体案例应用

堆排序(Heap Sort)是一种基于堆数据结构的排序算法。下面我将以分点表示和归纳的方式,结合相关数字和信息,详细描述堆排序的PTA(Programming and Testing Approach,编程与测试方法)。 1. 堆排序原理 堆排序是一种树形选择排序,利用了完全二叉树的性质,通过构建最大堆…...

pyspark中使用mysql jdbc报错java.lang.ClassNotFoundException: com.mysql.jdbc.Driver解决

报错信息&#xff1a; py4j.protocol.Py4JJavaError: An error occurred while calling o33.load. : java.lang.ClassNotFoundException: com.mysql.jdbc.Driver 我的解决方法&#xff1a; 这个报错就是提示你找不到jar包&#xff0c;所以你需要去下载一个和你mysql版本匹配的j…...

对称加密系统解析

目录​​​​​​​ 1.概述 2. 对称密码类型 3. 对称加密优缺点 4. 对称加密算法 4.1 DES 4.2 3DES 4.3 AES ​​​​​​4.4 SM1 4.5 SM4 1.概述 对称加密&#xff0c;是指在加密和解密时使用同一秘钥的方式。秘钥的传送和保存的保护非常重要&#xff0c;务必不要让秘…...

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

7.4.分块查找

一.分块查找的算法思想&#xff1a; 1.实例&#xff1a; 以上述图片的顺序表为例&#xff0c; 该顺序表的数据元素从整体来看是乱序的&#xff0c;但如果把这些数据元素分成一块一块的小区间&#xff0c; 第一个区间[0,1]索引上的数据元素都是小于等于10的&#xff0c; 第二…...

应用升级/灾备测试时使用guarantee 闪回点迅速回退

1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间&#xff0c; 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点&#xff0c;不需要开启数据库闪回。…...

Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?

Golang 面试经典题&#xff1a;map 的 key 可以是什么类型&#xff1f;哪些不可以&#xff1f; 在 Golang 的面试中&#xff0c;map 类型的使用是一个常见的考点&#xff0c;其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合

在汽车智能化的汹涌浪潮中&#xff0c;车辆不再仅仅是传统的交通工具&#xff0c;而是逐步演变为高度智能的移动终端。这一转变的核心支撑&#xff0c;来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒&#xff08;T-Box&#xff09;方案&#xff1a;NXP S32K146 与…...

JavaScript基础-API 和 Web API

在学习JavaScript的过程中&#xff0c;理解API&#xff08;应用程序接口&#xff09;和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能&#xff0c;使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...

根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的----NTFS源代码分析--重要

根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的 第一部分&#xff1a; 0: kd> g Breakpoint 9 hit Ntfs!ReadIndexBuffer: f7173886 55 push ebp 0: kd> kc # 00 Ntfs!ReadIndexBuffer 01 Ntfs!FindFirstIndexEntry 02 Ntfs!NtfsUpda…...

Unity VR/MR开发-VR开发与传统3D开发的差异

视频讲解链接&#xff1a;【XR马斯维】VR/MR开发与传统3D开发的差异【UnityVR/MR开发教程--入门】_哔哩哔哩_bilibili...

UE5 音效系统

一.音效管理 音乐一般都是WAV,创建一个背景音乐类SoudClass,一个音效类SoundClass。所有的音乐都分为这两个类。再创建一个总音乐类&#xff0c;将上述两个作为它的子类。 接着我们创建一个音乐混合类SoundMix&#xff0c;将上述三个类翻入其中&#xff0c;通过它管理每个音乐…...