【Leetcode】5.最长回文子串 【字符串、动态规划】

给定一个字符串 s s s,找到 s s s 中最长的回文子串。你可以假设 s s s 的最大长度为 1000 1000 1000

示例 1 1 1

输入: “ b a b a d babad babad
输出: “ b a b bab bab
注意: “ a b a aba aba” 也是一个有效答案。
示例 2 2 2

输入: “ c b b d cbbd cbbd
输出: “ b b bb bb

思路:

1)中心扩展算法。举个很简单的例子,字符串" a b a aba aba“是一个回文串,那么两边加上一个 x x x字符,即字符串为” x a b a x xabax xabax",那肯定也为回文串。那么这道题就可以这样解决,我们遍历字符串,将每个字符当作一个回文子串的中心点,向两边扩展,由于回文子串的长度可能为奇数也可能为偶数,则扩展方式就有两种,一种为奇数时的 ( i , i ) (i,i) (i,i)扩展,另一种为偶数时的 ( i , i + 1 ) (i,i+1) (i,i+1)扩展,判断两种方式扩展的长度大小,大的作为以该字符为中心点的回文子串的最大长度

class Solution {
public:
    string longestPalindrome(string s) {
        int length = s.size();
        if (length < 1)
            return "";
        int start = 0, end = 0;
        for (int i = 0; i < length; ++i) {
            int len1 = expandAroundCenter(s, i, i); //奇数扩展
            int len2 = expandAroundCenter(s, i, i + 1); //偶数扩展
            int len = max(len1, len2);  //比较两种方式扩展的最大长度
            //更新最大长度及回文子串的起始与结束
            if (len > end - start) {
                start = i - (len - 1) / 2;
                end = i + len / 2;
            } 
        }
        return s.substr(start, end - start + 1);
    }
    //向两边扩展
    int expandAroundCenter(string s, int left, int right) {
        while (left >= 0 && right < s.size() && s[left] == s[right]) {
            left--;
            right++;
        }
        return right - left - 1;
    }
};

2)动态规划方法。 d p [ i ] [ j ] = 1 dp[i][j] = 1 dp[i][j]=1表示 i − j i-j ij为回文子串,然后可以得到以下的状态转移方程:

  • d p [ i ] [ i ] = 1 dp[i][i] = 1 dp[i][i]=1,其本身字符当然为一个回文串
  • d p [ i ] [ i + 1 ] = 1 dp[i][i + 1] = 1 dp[i][i+1]=1 s [ i ] = = s [ i + 1 ] s[i] == s[i + 1] s[i]==s[i+1] && i &lt; n i &lt; n i<n
  • d p [ i ] [ i + l e n ] = d p [ i + 1 ] [ i + l e n − 1 ] dp[i][i + len] = dp[i + 1][i + len - 1] dp[i][i+len]=dp[i+1][i+len1] s [ i ] = = s [ i + l e n ] s[i] == s[i + len] s[i]==s[i+len] && i + l e n &lt; n i + len &lt; n i+len<n,即" x S x xSx xSx"是否为回文串依赖于 S S S是否为回文串
class Solution {
public:
    string longestPalindrome(string s) {
        int n = s.size();
        if (n < 2)
            return s;
        int start = 0, tlen = 1;
        int dp[n][n];
        memset(dp, 0, sizeof(dp));
        //初始化
        for (int i = 0; i < n; ++i) {
            dp[i][i] = 1;  //本身为回文串
            //满足条件相邻字符相等也为回文串
            if (i + 1 < n && s[i] == s[i + 1]) {
                tlen = 2;
                start = i;
                dp[i][i + 1] = 1;
            }
        }
        //从长度遍历,扩展回文串
        for (int len = 2; len < n; ++len) {
            for (int i = 0; i < n; ++i) {
                if (i + len < n && s[i] == s[i + len]) {
                    dp[i][i + len] = dp[i + 1][i + len - 1];
                    if (dp[i][i + len] && len + 1 > tlen) {
                        tlen = len + 1;
                        start = i;
                    }
                }
            }
        }
        return s.substr(start, tlen);
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值