[编程之美-07]最长回文子串

[Problem Description]
给定一个字符串,求它的最长回文子串的长度。

[Sample Input]
abcd
abbadef
defabaa

[Sample Output]
1
4
3

基本解法:回文字符串的概念我们已经在[编程之美-06]字符串回文判断 这篇博文中已经做了介绍,此题是让我们找出一个字符串中最长的回文字符串。假设这个字符串的长度为n,这n个都是一个回文字符串的中心点(最短长度为1),以这n个点为中心点,分别想左向右遍历,需要考虑回文字符串的长度是奇数还是偶数,此为核心问题。若为奇数,左右同时各走一步(条件:左右字符相同情况下);若为偶数,先判断中心点与其右边字符是否相等,而后左右同时各走一步(条件:左右字符相同情况下)。

代码如下:

#include<iostream>
#include<string>
using namespace std;

int longestPalindrome(const string s);

int main()
{
    string str;
    while(cin>> str)
    {
        cout<< longestPalindrome(str) <<endl;
    }
    return 0;
}

int longestPalindrome(const string s)
{
    if(s.length()==0)
        return 0;

    int curLength = 0, maxLength = 0;

    for(int i = 0; i < s.length(); i ++)
    {
        // 以i为中心点,回文串的长度是奇数 
        for(int j = 0; i-j >= 0 && i+j < s.length(); j ++)
        {
            if(s[i-j] != s[i+j])
                break;

            curLength = j*2 + 1;
        }

        if(curLength > maxLength)
            maxLength = curLength;

        // 以i为中心点,回文串的长度是偶数 
        for(int j = 0; i-j >= 0 && i+j < s.length()-1; j ++)
        {
            if(s[i-j] != s[i+j+1])
                break;

            curLength = j*2 + 2;
        }

        if(curLength > maxLength)
            maxLength = curLength;
    }

    return maxLength;
}

时间复杂度:O(n*n), 空间复杂度:O(1)

高效解法:基本解法的时间复杂度已经到O(n*n),既然存在高效解法,势必要牺牲空间来换时间,才可以将时间复杂度降低。
首先分析基本算法:外层for循环用于选择中心点,内层两边for循环分别考虑回文子串长度为奇数和偶数。首先我们考虑将回文子串长度全部变为奇数。 分别在字符串(举例:该字符串为“ABBABCBA”)中每个字符左右添加一个特殊标记字符(该特殊标记字符选择的原则:不会出现在原字符串中)。假设# 不会出现在原字符串中。则添加特殊标记字符后原字符串变为“#A#B#B#A#B#C#B#A#”,这样我们可以确保每个回文字符串的字符个数是奇数个。内层循环就可以解决了。接下来还需要优化的就是中心点的选择。原字符串“ABBABCBA” 每个字符都需要当作中心点 吗?答案肯定是不需要的。那么我们需要考虑中心点如何去滑动(PASS掉一些不必要的中心点)。增加两个辅助变量id,mx,其中,id表示最大回文子串中心的位置;mx表示最大回文子串的边界。p[i]表示以i为回文子串的中心位置,回文子串的长度。

[明天继续更新这篇博客]

    原文作者:caicaiatnbu
    原文地址: https://blog.csdn.net/caicaiatnbu/article/details/71914826
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞