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];}
};

 

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

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

相关文章

Spring AI 第二讲 之 Chat Model API 第六节Google VertexAI API

VertexAI API 可提供高质量的定制机器学习模型&#xff0c;只需花费最少的机器学习专业知识和精力。 Spring AI 通过以下客户端提供与 VertexAI API 的集成&#xff1a; VertexAI Gemini Chat Vertex AI Gemini API 允许开发人员使用 Gemini 模型构建生成式人工智能应用程序。…

Apollo9.0 PNC源码学习之Control模块(一)

0 前言 从planning的角度看control&#xff0c;首先需要了解的就是相关的数据接口&#xff0c;规划出的轨迹&#xff08;路径速度&#xff09;发给Control模块去执行 modules/planning/planning_component/planning_component.cc planning模块发布轨迹信息 planning_writer_ …

利用CSS隐藏HTML元素并插入替代内容

在创建一个支持切换阅读模式和答题模式的Anki问答题模板中&#xff0c;我创建了一个支持切换阅读模式和答题模式的问答题模板&#xff0c;该文最终利用JavaScript将Anki输出的向下箭头删除&#xff0c;并插入自定义的提示语。经过进一步测试&#xff0c;发现实现上述功能完全不…

Unity 从0开始编写一个技能编辑器_02_Buff系统的生命周期

工作也有一年了&#xff0c;对技能编辑器也有了一些自己的看法&#xff0c;从刚接触时的惊讶&#xff0c;到大量工作时觉得有一些设计的冗余&#xff0c;在到特殊需求的修改&#xff0c;运行效率低时的优化&#xff0c;技能编辑器在我眼中已经不再是神圣不可攀的存在的&#xf…

【微信小程序】开发环境配置

目录 小程序的标准开发模式&#xff1a; 注册小程序的开发账号 安装开发者工具 下载 设置外观和代理 第一个小程序 -- 创建小程序项目 查看项目效果 第一种&#xff1a;在模拟器上查看项目效果 项目的基本组成结构 小程序代码的构成 app.json文件 project.config…

燃料电池汽车践行者

前言 见《氢燃料电池技术综述》 见《燃料电池工作原理详解》 见《燃料电池发电系统详解》 见《燃料电池电动汽车详解》 见《氢燃料电池汽车行业发展》 现代汽车&#xff08;中国&#xff09; 现代汽车集团&#xff0c;自1998年成立氢燃料电池研发小组以来深耕氢燃料电池技术&am…

html+CSS+js部分基础运用19

1. 应用动态props传递数据&#xff0c;输出影片的图片、名称和描述等信息【要求使用props】&#xff0c;效果图如下&#xff1a; 2.在页面中定义一个按钮和一行文本&#xff0c;通过单击按钮实现放大文本的功能。【要求使用$emit()】 代码可以截图或者复制黏贴放置在“实验…

spring-data-mongodb版本兼容问题

spring-data-mongodb与mongodb驱动有兼容性问题&#xff0c;不匹配会报NoSuchMethod异常&#xff0c;mongodb的java驱动包在4.0之后由mongodb-java-driver更名为mongodb-driver-sync。 spring-data-mongodb包依赖中有mongodb-driver-core&#xff0c;但缺诸如MongoCollection等…

【C语言】文件操作(终卷)

前言 我们在上一卷中了解了顺序读写的函数&#xff0c;现在就让我们从随机读写的函数开始吧。 什么是随机读写&#xff1f; 就是想在哪个位置读或写都行&#xff0c;比较自由。文件打开时光标默认在起始位置。想从后面的某个部分读或写&#xff0c;就得让文件指针来到那个位…

VMware Fusion 如何增加linux硬盘空间并成功挂载

文章目录 0. 前言1. 增加硬盘空间2. 硬盘分区2.1 查看硬盘2.2 分区2.3 格式化2.4 挂载 3. 参考 0. 前言 如果发现虚拟机分配的硬盘不足&#xff0c;需要增加硬盘空间。本文教给大家如何增加硬盘空间并成功挂载。 查看当前硬盘使用情况&#xff1a; df -h可以看到&#xff0c…

什么是档案数字化管理

档案数字化管理指的是将传统的纸质档案转换为数字形式&#xff0c;并通过电子设备、软件和网络技术进行管理和存储的过程。 档案数字化管理包括以下几个步骤&#xff1a; 1. 扫描和数字化&#xff1a;将纸质档案通过扫描仪转换为数字图像或文档。可以使用OCR&#xff08;光学字…

[数据集][图像分类]人种黄种人白人黑人分类数据集970张4类别

数据集类型&#xff1a;图像分类用&#xff0c;不可用于目标检测无标注文件 数据集格式&#xff1a;仅仅包含jpg图片&#xff0c;每个类别文件夹下面存放着对应图片 图片数量(jpg文件个数)&#xff1a;970 分类类别数&#xff1a;4 类别名称:[“Asian”,“Caucasian”,“Indian…

什么是 AOF 重写?AOF 重写机制的流程是什么?

引言&#xff1a;在Redis中&#xff0c;持久化是确保数据持久性和可恢复性的重要机制之一。除了常见的RDB&#xff08;Redis Database&#xff09;持久化方式外&#xff0c;AOF&#xff08;Append Only File&#xff09;也是一种常用的持久化方式。AOF持久化通过记录Redis服务器…

基于Gabor小波特征提取和PSO-SVM的胃溃疡分类(MATLAB R2018a)

Gabor滤波器是在测不准原则下能够在时域和频域中唯一能取得最佳的联合分辨率函数&#xff08;测不准原则&#xff1a;是指在时域与频域中都要获得任何的测量精度那是不可能同时实现的&#xff0c;要使时域分辨率有所提高&#xff0c;必须牺牲频域的分辨率&#xff0c;反之亦然&…

Java | Leetcode Java题解之第134题加油站

题目&#xff1a; 题解&#xff1a; class Solution {public int canCompleteCircuit(int[] gas, int[] cost) {int n gas.length;int i 0;while (i < n) {int sumOfGas 0, sumOfCost 0;int cnt 0;while (cnt < n) {int j (i cnt) % n;sumOfGas gas[j];sumOfCos…

Polar Web【中等】search

Polar Web【中等】search Contents Polar Web【中等】search思路&探索首页一般注入方式 EXP&效果Payload 总结 思路&探索 见到题目标题&#xff0c;预测可能有目录扫描或者输入框查询数据之类情况&#xff0c;具体细节在破解过程中才能清楚 打开站点&#xff0c;显…

如何下载BarTender软件及详细安装步骤

BarTender是美国海鸥科技推出的一款优秀的条码打印软件&#xff0c;应用于 WINDOWS95 、 98 、 NT 、 XP 、 2000 、 2003 和 3.1 版本&#xff0c; 产品支持广泛的条形码码制和条形码打印机&#xff0c; 不但支持条形码打印机而且支持激光打印机&#xff0c;还为世界知名品牌条…

前端-a-date-picker如何设置禁选时间段

想要做到如图所示的效果&#xff0c;代码如下&#xff1a; 第一个是只能选择某一天&#xff0c;第二个是只能选择某一个时间段 <a-date-pickerv-model:value"record.onTimeStr":show-time"{ format: HH:mm }"valueFormat"YYYY-MM-DD HH:mm:ss&qu…

【RAG入门教程02】Langchian的Embedding介绍与使用

Embedding介绍 词向量是 NLP 中的一种表示形式&#xff0c;其中词汇表中的单词或短语被映射到实数向量。它们用于捕获高维空间中单词之间的语义和句法相似性。 在词嵌入的背景下&#xff0c;我们可以将单词表示为高维空间中的向量&#xff0c;其中每个维度对应一个特定的特征…

mm-qcamera-daemon主函数分析

目录 main函数核心 main函数核心 main函数的主要任务包含在一个do{ } while(1)循环中. while循环中主要是监听文件描述符,故mai函数是由文件的读写来进行驱动的。 所有的文件描述符被封装成结构体 read_fd_info_t.其定义如下&#xff1a; /** read_fd_info_t* type -- either …