LeetCode-5:Longest Palindromic Substring (最长回文字串)

题目:

Given a string s, find the longest palindromic substring in s.
You may assume that the maximum length of s is 1000.

例子:

Example1:

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

Example2:

Input: "cbbd"
Output: "bb"

问题解析:

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

链接:

  • LeetCode:

思路标签

动态规划中心扩展Manacher法

解答:

1.动态规划 O(n^2)

  • 利用动态规划的思想,将小问题逐步扩大到大问题,从而确定最长到回文字串;
  • 保存子串,则保存回文子串到首字母的位置以及回文字串的长度;
  • 定义dp[i][j]来表示字符串s[i]…s[j]的字串是否属于回文子串;
  • 如果dp[i+1][j-1] = true && s[i] == s[j]则说明,s[i]…s[j]为回文子串,dp[i][j] = true.
class Solution {
public:
    string longestPalindrome(string s) {
        string emptystr = "";
        int length = s.length();
        if (length == 1)
            return s;
        if (length == 0)
            return emptystr;

        bool dp[1000][1000] = {false};
        int maxsublength = 1;
        int start = 0;

        for (int i=0; i<length; ++i){
            dp[i][i] = true;
            if (i<length-1 && s.at(i) == s.at(i+1)){
                dp[i][i+1] = true;
                maxsublength = 2;
                start = i;
            }
        }

        for (int len=3; len <= length; ++len){
            for (int i=0; i<=length-len; ++i){
                int end = i + len - 1;
                if (s.at(i) == s.at(end) && dp[i+1][end-1]){
                    dp[i][end] = true;
                    if (len > maxsublength){
                        maxsublength = len;
                        start = i;
                    }
                }
            }
        }

        return s.substr(start, maxsublength);

    }
};

2. 中心扩展 O(n^2)

  • 将字符串的每一个字母作为中心,向两边扩展,找到的最长的子回文串即可;
  • 但是需要注意的是,我们需要分别考虑奇数和偶数的情况,如“aba”为奇数,”abba”为偶数。
class Solution {
public:
    string longestPalindrome(string s) {
        const int length = s.size();
        string  emptystr = "";
        if (length == 0)
            return emptystr;
        int maxlength = 1;
        int start = 0;

        //回文串为奇数个数的情况
        for (int i=0; i<length; ++i){
            int head = i-1, tail = i+1;
            while(head>=0 && tail<length && s.at(head) == s.at(tail)){
                if (tail-head+1 > maxlength){
                    maxlength = tail-head+1;
                    start = head;
                }
                head--;
                tail++;
            }
        }

        //回文串为偶数的情况
        for(int i=0; i<length; ++i){
            int head = i, tail = i+1;
            while(head>=0 && tail<length && s.at(head) == s.at(tail)){
                if(tail-head+1 > maxlength){
                    maxlength = tail-head+1;
                    start = head;
                }
                head--;
                tail++;
            }
        }

        return s.substr(start, maxlength); 

    }
};

3. Manacher O(n)

  • Manacher法只能解决例如aba这样长度为奇数的回文串,对于abba这样的不能解决,于是就在里面添加特殊字符。我是添加了“#”,使abba变为a#b#b#a。
  • 这个算法就是利用已有回文串的对称性来计算的,具体算法复杂度为O(N)
#define min(x, y) ((x)<(y)?(x):(y))
#define max(x, y) ((x)<(y)?(y):(x))
string findLongestPalindrome3(string s)
{
    int length=s.size();
    for(int i=0,k=1;i<length-1;i++)//给字符串添加 #
    {
        s.insert(k,"#");
        k=k+2;
    }
    length=length*2-1;//添加#后字符串长度
    int *rad=new int[length]();
    rad[0]=0;
    for(int i=1,j=1,k;i<length;i=i+k)
    {
        while(i-j>=0&&i+j<length&&s.at(i-j)==s.at(i+j))
            j++;
        rad[i]=j-1;
        for(k=1;k<=rad[i]&&rad[i-k]!=rad[i]-k;k++)//镜像,遇到rad[i-k]=rad[i]-k停止,这时不用从j=1开始比较
            rad[i+k]=min(rad[i-k],rad[i]-k);

        j=max(j-k,0);//更新j

    }
    int max=0;
    int center;
    for(int i=0;i<length;i++)
    {
        if(rad[i]>max)
        {
            max=rad[i];
            center=i;
        }
    }
    return s.substr(center-max,2*max+1);

}
点赞