代码随想录第60天 | 647. 回文子串 、 516.最长回文子序列

2024-05-05 10:04

本文主要是介绍代码随想录第60天 | 647. 回文子串 、 516.最长回文子序列,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、前言

参考文献:代码随想录;

转眼间两个月已经过去,五一休息了三天,今天将要结束动态规划了。

今天的主题是用dp解决回文子串;

二、回文子串

1、思路:

我一开始就想用一维dp数组来解决这道题目,但是发现找不到关系,然后就尝试使用了一下暴力解法,感觉不错;

(1)暴力:

class Solution {
private:bool isPalindrom(string &s, int start, int end) {while (start < end) {if (s[start] != s[end]) {return false;}start++;end--;}return true;}
public:int countSubstrings(string s) {int count = 0;for (int i = 0; i < s.size(); i++) {for (int j = i; j < s.size(); j++) {if (isPalindrom(s, i, j)) {count++;}}}return count;}
};

回到dp:

(1)递推公式 + 初始化:

我们需要判断改数组是不是回文串,所以我们定义的dp是bool类型,接着是我们需要一个边界来规定子串,这样才可以求出每个子串(这里顺带初始化了,全部都默认为false):

vector<vector<bool>> dp(s.size(), vector<bool> (s.size(), false));

 (2)递推公式:

我们需要判断三个条件,当i == j时,很显然一个字母也是回文串,所以为false;

当 j - i == 1时,也是一个回文串,例如“aba”;

当 j - i > 1时,我们就需要利用dp数组来解决了,判断 i + 1 到 j - 1这个区间是不是回文串,才能判断是不是回文串

(3)遍历顺序:

看这个图片发现,新的状态是之前的状态得出来的,但是这个状态在新状态的左下角,所以需要从下往上,从左往右遍历;

2、整体代码如下:

class Solution {
public:int countSubstrings(string s) {// 1、定义dp数组+初始化// 在下标i与j之间的范围内,是否是回文子串vector<vector<bool>> dp(s.size(), vector<bool> (s.size(), false));int count = 0;// 2、遍历顺序,从下往上,从左往右for (int i = s.size() - 1; i >= 0; i--) {for (int j = i; j < s.size(); j++) {// 3、递推公式(三种情况)if (s[i] == s[j]) {if (j - i <= 1 ) {dp[i][j] = true;} else {dp[i][j] = dp[i + 1][j - 1];}}if (dp[i][j]) count++;}}return count;}
};

三、最长回文序列

1、思路:

本题感觉有点小绕,所以我看了题解之后还是有点蒙蔽;

(1)dp数组定义:

可以看出这个与上一题目很像,但是求的是最长回文子串的长度,所以还是需要创建二维的int类型数组;

(2)递推公式:

分为两种情况,当 s[i] == s[j]时,就需要在原有的dp[i + 1][j - 1]的基础上加2;

(3)初始化:

首先要考虑当i 和j 相同的情况,从递推公式:dp[i][j] = dp[i + 1][j - 1] + 2; 可以看出 递推公式是计算不到 i 和j相同时候的情况。

所以要初始化这个对角线:

for (int i = 0; i < s.size(); i++) dp[i][i] = 1;

(4)遍历顺序:

这里的遍历还是从下到上,从左到右

 

 

 只是现在可以选择不连续的情况了,所以就如下(为什么不能把初始化的情况放到遍历中去?因为会越界,i == 0的时候就越界了):

for (int i = s.size() - 1; i >= 0; i--) {for (int j = i + 1; j < s.size(); j++) {if (s[i] == s[j]) {dp[i][j] = dp[i + 1][j - 1] + 2;} else {dp[i][j] = max(dp[i][j - 1], dp[i + 1][j]);}}}

2、完整代码如下:

class Solution {
public:int longestPalindromeSubseq(string s) {// 1、初始化+定义dp数组vector<vector<int>> dp(s.size(), vector<int> (s.size(), 0));for (int i = 0; i < s.size(); i++) dp[i][i] = 1;// 2、遍历顺序for (int i = s.size() - 1; i >= 0; i--) {for (int j = i + 1; j < s.size(); j++) {if (s[i] == s[j]) {dp[i][j] = dp[i + 1][j - 1] + 2;} else {dp[i][j] = max(dp[i][j - 1], dp[i + 1][j]);}}}return dp[0][s.size() - 1];}
};

Study time 1h

Leave message:

Young people have changed the course of history time and time again.

年轻人一次又一次的改变了历史的进程。

 

这篇关于代码随想录第60天 | 647. 回文子串 、 516.最长回文子序列的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/961435

相关文章

poj2406(连续重复子串)

题意:判断串s是不是str^n,求str的最大长度。 解题思路:kmp可解,后缀数组的倍增算法超时。next[i]表示在第i位匹配失败后,自动跳转到next[i],所以1到next[n]这个串 等于 n-next[n]+1到n这个串。 代码如下; #include<iostream>#include<algorithm>#include<stdio.h>#include<math.

poj3261(可重复k次的最长子串)

题意:可重复k次的最长子串 解题思路:求所有区间[x,x+k-1]中的最小值的最大值。求sa时间复杂度Nlog(N),求最值时间复杂度N*N,但实际复杂度很低。题目数据也比较水,不然估计过不了。 代码入下: #include<iostream>#include<algorithm>#include<stdio.h>#include<math.h>#include<cstring

spoj705( 求不相同的子串个数)

题意:求串s的不同子串的个数 解题思路:任何子串都是某个后缀的前缀,对n个后缀排序,求某个后缀的前缀的个数,减去height[i](第i个后缀与第i-1 个后缀有相同的height[i]个前缀)。 代码如下: #include<iostream>#include<algorithm>#include<stdio.h>#include<math.h>#include<cstrin

csu1328(近似回文串)

题意:求近似回文串的最大长度,串长度为1000。 解题思路:以某点为中心,向左右两边扩展,注意奇偶分开讨论,暴力解即可。时间复杂度O(n^2); 代码如下: #include<iostream>#include<algorithm>#include<stdio.h>#include<math.h>#include<cstring>#include<string>#inclu

活用c4d官方开发文档查询代码

当你问AI助手比如豆包,如何用python禁止掉xpresso标签时候,它会提示到 这时候要用到两个东西。https://developers.maxon.net/论坛搜索和开发文档 比如这里我就在官方找到正确的id描述 然后我就把参数标签换过来

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n

uva 10131 最长子序列

题意: 给大象的体重和智商,求体重按从大到小,智商从高到低的最长子序列,并输出路径。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vect

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能

代码随想录冲冲冲 Day39 动态规划Part7

198. 打家劫舍 dp数组的意义是在第i位的时候偷的最大钱数是多少 如果nums的size为0 总价值当然就是0 如果nums的size为1 总价值是nums[0] 遍历顺序就是从小到大遍历 之后是递推公式 对于dp[i]的最大价值来说有两种可能 1.偷第i个 那么最大价值就是dp[i-2]+nums[i] 2.不偷第i个 那么价值就是dp[i-1] 之后取这两个的最大值就是d