【最长回文子串和子序列】LeetCode5

1.题目(最长回文子串)

Given a string s, return the longest palindromic substring in s.

Example 1:

Input: s = "babad"
Output: "bab"
Note: "aba" is also a valid answer.

Example 2:

Input: s = "cbbd"
Output: "bb"

Example 3:

Input: s = "a"
Output: "a"

Example 4:

Input: s = "ac"
Output: "a"

2.思路

2.1迭代法(暴力法)

循环遍历,找以S[i]为中心的最大回文子串,最后遍历一遍字符串找最大回文子串即可,复杂度O(N^2)

3.代码

3.1 迭代法

class Solution {
public:
    string maxrev(string s,int a,int b)
    {
        while((a>=0)&&(b<s.size())&&(s[a]==s[b]))
              {
                  a--;
                  b++;
              }
       // cout<<a<<"a"<<" "<<b<<"b"<<"kk";
       // cout<<s.substr(a+1,b-a-1)<<endl;
        return s.substr(a+1,b-a-1);
    }
    
    string longestPalindrome(string s)
    {
      //遍历法
        int num=s.size();
        string maxs="";
        for(int i=0;i<num;i++)
        {
            
            string s1=maxrev(s,i,i);
            string s2=maxrev(s,i,i+1);
            if(maxs.size()<s1.size())
                maxs=s1;
            if(maxs.size()<s2.size())
                maxs=s2;
        }
        
        return maxs;
        
        
    }
};

3.2 dp法

class Solution {
public:
    string longestPalindrome(string s) {
         int dp[1005][1005];
        int num=s.size();
       for(int i=0;i<num;i++)
    {
        int j=i;
        dp[i][j]=1;
        
    }
   for(int i=0;i<num-1;i++)
   {
       int j=i+1;
       if(s[i]==s[j])
           dp[i][j]=1;
       else dp[i][j]=0;
   }
    for(int i=num-3;i>=0;i--)
    {
        for(int j=i+2;j<num;j++)
        {
            if(s[i]==s[j])
                dp[i][j]=dp[i+1][j-1];
            else 
                dp[i][j]=0;
        }
    }
        
         int max=0;int a=0;int b=0;
        for(int i=0;i<s.size();i++)
        {
          for(int j=0;j<s.size();j++)    
          {
             // cout<<dp[i][j]<<" ";
             if((dp[i][j]==1)&&(max<j-i+1))
             {
                 max=j-i+1;
                 a=i;
                 b=j;
              }
          }
           // cout<<endl;
        }
        return s.substr(a,b-a+1);
        
    }
};

4.题目二(最长回文子序列)

Given a string s, find the longest palindromic subsequence’s length in s.

A subsequence is a sequence that can be derived from another sequence by deleting some or no elements without changing the order of the remaining elements.

Example 1:

Input: s = "bbbab"
Output: 4
Explanation: One possible longest palindromic subsequence is "bbbb".

Example 2:

Input: s = "cbbd"
Output: 2
Explanation: One possible longest palindromic subsequence is "bb".

5.思路(二维dp)

我们说这个问题对 dp 数组的定义是:在子串s[i…j]中,最长回文子序列的长度为dp[i][j]。一定要记住这个定义才能理解算法。
具体来说,如果我们想求dp[i][j],假设你知道了子问题dp[i+1][j-1]的结果(s[i+1…j-1]中最长回文子序列的长度),你是否能想办法算出dp[i][j]的值(s[i…j]中,最长回文子序列的长度)呢?

可以!这取决于s[i]和s[j]的字符:

如果它俩相等,那么它俩加上s[i+1…j-1]中的最长回文子序列就是s[i…j]的最长回文子序列:

如果它俩不相等,说明它俩不可能同时出现在s[i…j]的最长回文子序列中,那么把它俩分别加入s[i+1…j-1]中,看看哪个子串产生的回文子序列更长即可

以上两种情况写成代码就是这样:

if (s[i] == s[j])
    // 它俩一定在最长回文子序列中
    dp[i][j] = dp[i + 1][j - 1] + 2;
else
    // s[i+1..j] 和 s[i..j-1] 谁的回文子序列更长?
    dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]);

至此,状态转移方程就写出来了,根据 dp 数组的定义,我们要求的就是dp[0][n - 1],也就是整个s的最长回文子序列的长度。

【注意】!!!首先明确一下 base case,如果只有一个字符,显然最长回文子序列长度是 1,也就是dp[i][j] = 1,(i == j)。

因为i肯定小于等于j,所以对于那些i > j的位置,根本不存在什么子序列,应该初始化为 0。
在这里插入图片描述

6.dp代码

dp[i][j]对应关系一定画图,不要想当然!!!不然很容易对应错
另外状态转换关系是加2!!!

class Solution {
public:
    int longestPalindromeSubseq(string s) 
    {
      int num=s.size();
      int dp[1005][1005];
        memset(dp,0,sizeof(dp));
        //fill(dp[0],dp[0]+1005*1005,0);
        //basecase
    for(int i=0;i<num;i++)
    {
        int j=i;
        dp[i][j]=1;
        
    }
     //开始反着遍历
    for(int i=num-2;i>=0;i--)
    {
        for(int j=i+1;j<num;j++)
        {
            if(s[i]==s[j])
            dp[i][j]=dp[i+1][j-1]+2;
            else 
                dp[i][j]=max(dp[i+1][j],dp[i][j-1]);
        }
    }
        
    return dp[0][num-1];
        
        
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值