当前位置:   article > 正文

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

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

把夜熬成粥,然后喝了它。

——2024年7月1日


书接上回:区间动态规划——最长回文子串(C++)-CSDN博客,大家有想到解决办法吗?

题目描述

        给定一个字符串s(s仅由数字和英文大小写字母组成,长度为1~1000),求s中最长的回文子序列长度。例如,s = “aferegga”,最长的回文子序列为“aerea”,其长度为5。


题解思路

        区间动态规划

下面是个人的思路:

1. 定义dp数组

        定义 dp[i][j]表示 s[i...j] 中最长回文子序列长度。

2. 确定dp限制条件

注:len表示字符串长度

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

        ②对于任何 len == 2 的字符串,dp[i][j] = dp[i][j-1] + (s[i] == s[j]);

        ③对于任何 len  ≥  3 的字符串,有两种情况:

        如果 s[i] == s[j],那么dp[i][j] = dp[i+1][j-1] + 2

        如果 s[i] != s[j],那么dp[i][j] = max(dp[i+1][j],dp[i][j-1])

解释如下:

        第一种情况,如果字符串长度为1的话,那么它一定是回文子串,长度唯一;

        第二种情况,如果字符串长度为2,那它就有两种可能,要么这两个字符相等,要么不等,不管哪一种情况,这个字符串的回文子序列至少是大于等于1的(第一种情况),如果相等,无非是把这个相等的加上即可。

        第三种情况,字符串长度不小于3时,也有两种可能:
        如果 s[i] == s[j],那么当前最长回文子序列长度就等于上一次的回文子序列长度加上2(两个相同的字符),也可以表示为dp[i][j] = dp[i+1][j-1] + 2*(s[i] == s[j])
        如果 s[i] != s[j],那么当前最长回文子序列长度至少是在 s[i+1....j]和s[i....j-1]中取最大值,即dp[i][j] = max(dp[i+1][j],dp[i][j-1])


推导过程

用矩阵推导如下:

 

代码展示

  1. // 最长回文子序列长度
  2. int getLongestPalind(string s){
  3. int size = s.size();
  4. vector<vector<int>> dp(size, vector<int> (size, 0));
  5. // 定义dp数组
  6. // dp[i][j]表示从i到j的最长子回文字符串长度
  7. for(int len = 1; len <= size; len++){
  8. for(int i = 0; i + len - 1 < size; i++){
  9. int j = i + len - 1;
  10. if(len == 1){
  11. dp[i][j] = 1;
  12. }
  13. else if(len == 2){
  14. dp[i][j] = dp[i][j-1] + (s[i] == s[j]);
  15. }
  16. else{
  17. if(s[i] == s[j]){
  18. dp[i][j] = dp[i+1][j-1] + 2 * (s[i] == s[j]);
  19. }
  20. else{
  21. dp[i][j] = max(dp[i+1][j], dp[i][j-1]);
  22. }
  23. }
  24. }
  25. }
  26. return dp[0][size-1];
  27. }

运行结果

完整代码

  1. // 区间动态规划
  2. #include<iostream>
  3. #include<vector>
  4. #include<string>
  5. using namespace std;
  6. // 最长回文子序列长度
  7. int getLongestPalind(string s){
  8. int size = s.size();
  9. vector<vector<int>> dp(size, vector<int> (size, 0));
  10. // 定义dp数组
  11. // dp[i][j]表示从i到j的最长子回文字符串长度
  12. for(int len = 1; len <= size; len++){
  13. for(int i = 0; i + len - 1 < size; i++){
  14. int j = i + len - 1;
  15. if(len == 1){
  16. dp[i][j] = 1;
  17. }
  18. else if(len == 2){
  19. dp[i][j] = dp[i][j-1] + (s[i] == s[j]);
  20. }
  21. else{
  22. if(s[i] == s[j]){
  23. dp[i][j] = dp[i+1][j-1] + 2 * (s[i] == s[j]);
  24. }
  25. else{
  26. dp[i][j] = max(dp[i+1][j], dp[i][j-1]);
  27. }
  28. }
  29. }
  30. }
  31. return dp[0][size-1];
  32. }
  33. int main(){
  34. string s;
  35. cout<<"请输入字符串s:";
  36. cin>>s;
  37. cout<<"最长回文子序列长度为"<<getLongestPalind(s)<<endl;
  38. return 0;
  39. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/神奇cpp/article/detail/798503
推荐阅读
相关标签
  

闽ICP备14008679号