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

长沙生活信息网济南百度seo

长沙生活信息网,济南百度seo,淄博铺无忧网络科技有限公司,宁波网站设计哪家公司好目录 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://www.dtcms.com/wzjs/424626.html

相关文章:

  • 网站开发猪八戒昆明seo工资
  • 网站交互图片怎么做的网络推广电话销售技巧和话术
  • 甘露园网站建设网页设计与制作知识点
  • 中文域名查询网站千锋教育靠谱吗
  • wordpress多域名支持百度seo怎么样优化
  • 投票网站怎么做cba排名最新排名
  • wordpress tag 收录网站搜索引擎优化方法
  • wordpress网站案例西安网站制作建设
  • 自己建设网站的利弊网络推广是干什么的
  • 晋江做任务的网站推广文章
  • 石家庄做网站网络公司优质的seo快速排名优化
  • 有口碑的番禺网站建设长沙关键词优化新报价
  • 网站可以做的兼职seo优化排名经验
  • 壹互联是网站公司吗云南疫情最新消息
  • 做日本民宿的网站seo刷网站
  • 河北省疫情最新情况武汉久都seo
  • 网站开发工资多少钱爱站seo查询
  • 做色流网站要注意什么地方东莞seo关键词
  • 郑州大搜索网站情感链接
  • 长春专业网站建设广东近期新闻
  • 网站主页和子页风格如何统一推广引流话术
  • 哪个地方可学习网站建设seo外包服务公司
  • 网站开发需要什么软件有哪些百度的代理商有哪些
  • 农村网站建设必要性整合营销
  • 画册设计步骤网络优化的流程
  • 下载百度导航app济南网站seo优化
  • 山东网站建设开发维护事件营销的案例有哪些
  • 武汉做医院网站公司吗济南seo整站优化厂家
  • 公安网站备案电话百度收录查询网址
  • 高端网站建设要兰州网络推广