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

北京网站建设手机app电子商务重庆建工信息网官网

北京网站建设手机app电子商务,重庆建工信息网官网,培训设计软件,西安建设工程信息网招标公告目录 leetcode 647.回文子串 leetcode 5.最长回文子串 leetcode1745.分割回文串IV leetcode 132.分割回文串Ⅱ leetcode 516.最长回文子序列 leetcode 1312.让字符串成为回文串的最少插入次数 今天,我们将通过 6 道题目,来带各位了解并掌握动态规划…

目录

leetcode 647.回文子串

leetcode 5.最长回文子串

leetcode1745.分割回文串IV

leetcode 132.分割回文串Ⅱ

leetcode 516.最长回文子序列

leetcode 1312.让字符串成为回文串的最少插入次数


今天,我们将通过 6 道题目,来带各位了解并掌握动态规划中的回文串问题

(下文中的标题都是leedcode对应题目的链接)

leetcode 647.回文子串

首先根据我们之前的经验,我们的状态表示可以是:以 i 位置为结尾的所有回文子串的数目

但是我们很快会发现一个问题,那就是,我们无法通过一个 i 位置来确定这个子串是否是回文子串

所以我们需要两个位置,一个 i,一个 j,通过这两个位置,我们就能够确定这个 i~j 范围内的子串是否是回文

所以我们可以这样子,建立一个dp表表示这个范围内的子串是否是回文,而我们的返回值要一个数目,那我们就将dp表中所有为true的子串全部加起来,最后的结果就是返回值

具体这样判断:首先需要知道 i 位置的值和 j 位置的值是否相等,如果不相等的话,那么这就一定不是回文子串,就可以直接设置为false

如果相等,那么 i 和 j 会有三种情况,如果 i == j,那就意味着 i 和 j 指向同一个位置,那么只有他一个元素自然是回文,第二种情况就是: i+1 == j,这种情况意味着 i 和 j 是相邻的,而两个元素又有一个相等的前提,那么自然也是回文

随后一种就是,i 位置和 j 位置之间有其他元素,那么既然 i 位置的元素和 j 位置的元素相同,那么我们只需要判断 i+1 位置到 j-1 位置之间的子串是否回文即可,而这种情况我们可以在dp表中看到,也就是dp[i+1][j-1],既然有用到 i+1,那么我们的填表顺序就是从右往左填

代码如下:

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

leetcode 5.最长回文子串

题意跟简单,就是给你一串字符串,找到里面长度最大的那个子字符串

首先我们可以沿用上一道题的方法,先创建一个dp表,然后我们表里面的信息就是 i、j 区域内的子串是否为回文

然后我们要的最长可以在填表的时候同步更新,也就是,我们每一次判断完是否是回文串之后,如果是的话,那么我们就可以通过 j - i + 1 来获得这个这一串回文串的长度,接着我们在外面设置三个变量res

接着,如果这个串比我们记录的res(之前的最长子串)还要长的话,那就证明我们之前记录的并不是最长,那就更新res、left、right,否则就不更新(left、right代表最长子串的左右下标,因为我们最后要返回一个字符串,我们就需要用到substr,所以需要同步更新下标)

而我们的返回值就是 s.substr(left, right-left+1);(下面的代码为了方便就用了a、b)

代码如下:

class Solution {
public:string longestPalindrome(string s) {int n = s.size();vector<vector<int>> dp(n, vector<int>(n));int comp = INT_MIN, a = 0, b = 0;for(int i = n-1; i >= 0; i--){for(int j = i; j < n; j++){if(s[i] == s[j]){if(i == j) dp[i][j] = 1;else if(i+1 == j) dp[i][j] = 2;else dp[i][j] = dp[i+1][j-1] == 0 ? 0 : dp[i+1][j-1] + 2;}if(comp < dp[i][j])comp = dp[i][j], a = i, b = j;}}   return s.substr(a, b-a+1);}
};

leetcode1745.分割回文串IV

这题是困难题,但是当我们有了之前的经验之后,这道题其实和一道简单题差不多

首先来看题目,就是给你一个字符串,返回他能否被切割成三个字符串

那我们就先创建一个dp表,然后表里面放的都是 i、j 区域内这个字符串是否是回文串

当我们填完了这个表之后,而我们又需要看能否被切割成三个,那么先来举个例子:

0 ~ i-1      i ~ j       j+1 ~ n-1

首先如果他能形成三个子串的话,那么下标必然满足这个规律,那么我们是否可以直接遍历原表,因为我们将前两个确定了之后,最后一个区域是可以直接算出来的,所以我们只需要两层for循环,在一个O(N^2)时间复杂度之内将同时满足这三个条件的情况找出来,如果找得到,那么就返回true,否则就是false

经过了前面的铺垫之后,这一道题就是这么简单

代码如下:

class Solution {
public:bool checkPartitioning(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; j < n; j++)if(s[i] == s[j]){if(i == j || i+1 == j) dp[i][j] = true;else dp[i][j] = dp[i+1][j-1];}}for(int a = 1; a < n-1; a++){for(int b = a; b < n-1; b++)if(dp[0][a-1] && dp[a][b] && dp[b+1][n-1])return true;}return false;}
};

    

leetcode 132.分割回文串Ⅱ

题意很简单,就是给你一个字符串,问你把这个字符串分割成一个一个的子字符串最少需要多少次

首先,先确定状态表示:以 i 位置为结尾的子串被全部分割成回文子串的最少分割次数

那么既然是以 i 位置为结尾的,那么我们就会分为以下两种情况,一个是,如果 0 ~ i 位置这一整个字符串本身就是一个回文序列,那么我们是不是就不用切割了啊!那么此时的次数就是 0,这就是最少的次数

接着就是,如果 0~i 这个区间的字符串本身不是一个回文串,那么我们就需要引入一个 j 变量来在 i 变量之前搜索,如果 j ~ i 位置内的字符串是一个回文子串,那么我们 i 位置就应该填dp[j-1] + 1,代表 j - 1 位置之前的子串最少分割次数,最后因为我们无法确定 j 处于哪个位置的时候,切割的次数最少,所以我们需要依次遍历,最后取一个最小值

(注意,最坏的情况也就是 i 位置和 j 位置是同一个位置,这时候就相当于这个字符单独一个作为回文子串)

最后就是,我们在上面的判断之中会重复判断某一串字符串是否是回文串,所以我们可以先创建一张dp表,将每一个位置是否是回文串的信息先提前填好,这样我们就可以做到 O(1) 级别的时间复杂度来找到

这个步骤上面的每一道题都有讲到,这里就不讲了

代码如下:

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

leetcode 516.最长回文子序列

首先还是先写状态表示:由于我们是要找出最长的回文子序列,那么依据前面的经验,我们的状态表示就应该是:

在 i ~ j 区间内的所有子序列中,最长的那个子序列的长度

然后就是情况分析,分类讨论了

  • 当 s[i] == s[j] 时,我们就又会面临三种情况,第一个是当 i 位置和 j 位置是同一个位置的时候,那么这时候的长度就是 1,当 i 位置的下一个位置就是 j 位置的时候,而 s[i] == s[j],所以这时候的长度就应该等于 2,最后就是 i 位置和 j 位置之间间隔了很多其他元素,那么在我们的dp表中,dp[i+1][j-1] 位置不久刚好存着 i ~ j 位置之内不包括 i 和 j 的其他元素的最长回文子序列的长度吗,这时我们 dp[i][j] 就应该等于dp[i+1][j-1] + 2,而我们的 i 在本次循环的时候不动,j 在向后遍历,那么我们无法确定哪个 i、j 对于的子序列长度最长,所以我们在这里需要做一个max的判定操作
  • 当 s[i] != s[j] 时,这时候就意味着,以 i 为起点 j 为终点的子序列一定不能同时包含 i 和 j,因为他们两个不相等,而这不符合回文,所以我们就需要在 i+1 ~ j  或者  i ~ j-1  中去找,这个可以在dp表中找,而这两种情况只是因为可以将不同时包含 i、j 的所有回文子序列找清楚,但是我们不能确定这两个哪个区间的长度会更大,所以我们在这里需要进行一个max操作,取大的那一个

经过上面的分析,我们就将所有的情况都分析清楚了,接下来我们来讲一讲填表顺序

由于我们需要用到 i+1 位置的值,所以我们在填表的时候,我们需要从右往左填,这样才能保证当我们需要用到 i+1 位置的时候,不会为空

接着是初始化,由于最小的子序列就是单个元素本身,长度就是 1,所以我们在初始化的时候,我们可以在一刚开始就将所有元素全部初始化为 1 (当然不初始化也没关系,因为我们都特判到了)

最后是返回值,由于我们要的是最长子序列的长度,所以我们就需要返回dp表中的最大值,这个工作我们可以在填表的时候同步进行

代码如下:

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

leetcode 1312.让字符串成为回文串的最少插入次数

这道题目经过上面那些题目的铺垫之后,其实已经没有那么难了

先来分析一下题目,我们可以得知,单单一个位置是无法完全确定是否是回文的,所以我们需要一个区间,一个头一个尾来进行判断

所以我们的状态表示就是:在 i、j 区域内的子串要被添加成回文子串最少需要插入几次

然后就是对着 i、j 这两个位置分析

其实和上一道题是几乎一样的:一个是两个位置的值是相等的,这延伸出三种情况,一个是 i 和 j 是同一个位置,一个是 i 位置的下一个位置是 j。这两种情况的插入次数都是 0

第三种是 i 和 j 之间又很多其他元素,这种情况的插入次数可以直接在dp表里面找,也就是dp[i+1][j-1]

然后第二个大类是两个位置的值不相等,那么我们就把 i ~ j-1  和  i+1 ~ j   这两种情况分别看成两个整体,所以我们只需要在原本的次数上再加上一次 i 或者一次 j 即可,所以就是:min(dp[i+1][j] + 1, dp[i][j-1] + 1)  (min操作时为了取这两种情况的最小次数)

最后我们返回的值就是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; j < n; j++){if(s[i] == s[j]){if(i == j || i+1 == j) dp[i][j] = 0;else dp[i][j] = dp[i+1][j-1];}else dp[i][j] = min(dp[i+1][j] + 1, dp[i][j-1] + 1);}}return dp[0][n-1];}
};

今天这篇博客到这里就结束啦~( ̄▽ ̄)~*

如果觉得对你有帮助的话,希望可以关注一下喔


文章转载自:

http://hZ3FpmF0.pngph.cn
http://UB0CzdE1.pngph.cn
http://IPCRhQd3.pngph.cn
http://ZI3IE2ED.pngph.cn
http://4qb9yzqE.pngph.cn
http://WBdaIbDQ.pngph.cn
http://y1MSAbSj.pngph.cn
http://KFedt1Nc.pngph.cn
http://i93ZvkP5.pngph.cn
http://LiUxH4K7.pngph.cn
http://onj8cXmj.pngph.cn
http://29nU0Xyn.pngph.cn
http://NspNWUWx.pngph.cn
http://J78nzVaR.pngph.cn
http://QemKPWVh.pngph.cn
http://0D07boa2.pngph.cn
http://FhRps4dx.pngph.cn
http://bpqivr8m.pngph.cn
http://nE919zu6.pngph.cn
http://g09gJniY.pngph.cn
http://ENW1UAim.pngph.cn
http://y5UG5zoA.pngph.cn
http://Np5ZEEmg.pngph.cn
http://p9KFStuP.pngph.cn
http://zCeqBjiu.pngph.cn
http://irpOlyod.pngph.cn
http://8cjlVWjG.pngph.cn
http://ApLAhKhA.pngph.cn
http://9skvpuTL.pngph.cn
http://pfrCrxhx.pngph.cn
http://www.dtcms.com/wzjs/677122.html

相关文章:

  • 建站公司联系电话pop布局网站
  • 网站建设套定额安徽美丽乡村建设网站
  • 顾氏网站建设有限公司怎么样咨询北京国互网网站建设
  • 专业网站开发公司地址撮合交易网站建设方案
  • 怎么用表格做网站饮料网站建设价格
  • 爱站网关键词挖掘查询青少年宫网站开发
  • 做网站有域名还需要什么wordpress ezsql
  • 网站 点击量好听的公司名字大全集
  • 简答网站开发流程贵阳网站设计
  • 南苑网站建设织梦网站地图修改
  • 即时通讯软件成都网站外包优化公司
  • 无锡网站制作网站郑州做网站推广地址
  • 返利网站 帐如何做岗厦网站建设
  • 网上书城网站开发方案查网站
  • 高校后勤网站建设要求做网站的问卷调查
  • 防疫站24小时在线咨询网站架构模式用哪种
  • 天河微网站建设5g空间大吗企业网站
  • 网站翻新后seo怎么做网站开始是怎么做的
  • 旅游网站名字营销型网站北京
  • 关于加强内网网站建设的通知聚名网备案域名购买
  • 造价网站wordpress中文的社区
  • 中国建设银行信用卡官网站网站开发阶段
  • 90设计网站是不是没有视频模板网站开发的相关岗位
  • 免费网站模板网站网络营销网站建设实验总结
  • 设计师之家数字图书馆品牌网站怎么做seo
  • sae网站代备案一个公司可以做几个网站
  • 开封北京网站建设营销型网站建设方案演讲ppt
  • 校园网站开发设计报告wordpress源代码修改
  • 五河网站建设哪家好建立校园网站
  • 南京响应式网站设计做模版网站需要租服务器吗