当前位置: 首页> 科技> 能源 > 区间动态规划——最长回文子串(C++)

区间动态规划——最长回文子串(C++)

时间:2025/7/30 19:40:29来源:https://blog.csdn.net/m0_73962294/article/details/140086142 浏览次数:0次

难得心静。

——2024年6月30日


  什么是区间动态规划?

        区间动态规划通常以连续区间的求解作为子问题,例如区间 [i, j] 上的最优解用dp[i][j]表示。先在小区间上进行动态规划得到子问题的最优解,再利用小区间的最优解合并产生大区间的最优解
        所以区间动态规划一般需要从小到大枚举所有可能的区间,在枚举时不能向平常的从头到尾遍历,而是以区间长度len为循环变量,在不同的区间长度中枚举所有的可能状态,并从中选取最优解。

区间动态规划区别于一般的动态规划:以区间长度len作为循环变量。 


下面以LeetCode5最长回文子串为例:

LeetCode5——最长回文子串

题目描述

        给定一个字符串s(s仅由数字和英文大小写字母组成,长度为1~1000),求s中最长的回文子串。例如,s = “babad”,最长的回文子串有“bab”和“aba”,求出任意一个均可。

题解思路

        区间动态规划

1. 定义dp数组

        定义 dp[i][j ]表示 s[i...j] 是否为回文子串,dp的数值用true和false表示。例如 s = “aba”,那么dp[0][2] = true,dp[0][1] = false;

动态规划的问题,dp的含义都是自己给的,给出含义之后就需要去列关系求解了。

2. 确定dp限制条件

注:len表示字符串长度

        ①对于任何 len == 1 的字符串,dp[i][j] = 1

        ②对于任何 len == 2 的字符串,dp[i][j] = (s[i] == s[j]);(如果s[i] == s[j], 说明该长度为2的字符串是回文串,比如说“aa”)

        ③对于任何 len  ≥  3 的字符串, dp[i][j] = (dp[i+1][j-1] && s[i] == s[j])

解释如下:

        第一种情况很好理解,如果字符串长度为1的话,那么他一定是回文子串;

        第二种情况也很好理解,如果字符串长度为2,那么只需要判断这两个字符是否相等即可,如果相等则为回文子串,反之则不是;

        第三种情况,字符串长度不小于3时,你就需要想到你定义的dp含义和回文字符串的性质了,dp[i][j ]表示 s[i...j] 是否为回文子串要判断s[i...j]是否为回文子串,那么就必须先知道s[i+1...j-1]是否为回文子串,然后再判断s[i]是否等于s[j],两者都满足的话那dp[i][j]就等于true了,只要有一个不满足,那么dp[i][j]就为false。

Tips

        前两种情况是小区间的最优解,第三种情况就是大区间的最优解。

        其实动态规划的问题本质上就是求取了子问题的最优解之后,不断根据子问题的值更新当前dp数组的值,比如非常经典的背包问题。

3. 更新目标字符串长度

        不断更新目标字符串长度,只要出现 dp[i][j]=true 的情况就进行更新,并利用substr函数打印即可。(这里如果不理解请看代码部分) 


 代码实现

再次提醒:区间动态规划的特点是以len为循环变量

区间动态规划伪代码:

for(int len = 1; len <= 序列长度; len++){for(int i = 0; i + len - 1 < 序列长度; i++){int j = i + len - 1;i和j就是区间的端点,i与j相距len个长度。}
}

关键代码:

// 获取最长回文子串
string getLongestStr(string s){int n = s.size();string ans = "";// 定义dp数组// dp[i][j]表示从i到j的子字符串是否为回文串vector<vector<bool>> dp(n, vector<bool> (n, false));// len从1开始for(int len = 1; len <= n; len++){for(int i = 0; i + len - 1 < n; i++){int j = i + len - 1;if(len == 1){dp[i][j] = true;}else if(len == 2){dp[i][j] = (s[i] == s[j]);}else{dp[i][j] = (s[i] == s[j] && dp[i+1][j-1]);}if(dp[i][j] && ans.size() < len){ans = s.substr(i, len);//更新回文子串}}}return ans;
}

结果展示

 

完整代码

// 区间动态规划
#include<iostream>
#include<vector>
#include<string>using namespace std;// 获取最长回文子串
string getLongestStr(string s){int n = s.size();string ans = "";// 定义dp数组// dp[i][j]表示从i到j的子字符串是否为回文串vector<vector<bool>> dp(n, vector<bool> (n, false));// len从1开始for(int len = 1; len <= n; len++){for(int i = 0; i + len - 1 < n; i++){int j = i + len - 1;if(len == 1){dp[i][j] = true;}else if(len == 2){dp[i][j] = (s[i] == s[j]);}else{dp[i][j] = (s[i] == s[j] && dp[i+1][j-1]);}if(dp[i][j] && ans.size() < len){ans = s.substr(i, len);}}}return ans;
}int main(){string s;cout<<"请输入字符串s:";cin>>s;cout<<"最长回文子串为"<<getLongestStr(s)<<endl;return 0;
}

         看完了是否意犹未尽呢,那再把这个题变一下 ,我现在想求最长回文子序列(或者它的长度)应该怎么做?题目解释:比如我有一个字符串为:s = “aferegga”,那它的最长回文子序列为“aerea”,它的长度为5。

关键字:区间动态规划——最长回文子串(C++)

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: