四种方法求最长回文串

所谓回文串,就是正着读和倒着读结果都一样的回文字符串。
比如:
a, aba, abccba都是回文串,
ab, abb, abca都不是回文串。

一、暴力法

最容易想到的就是暴力破解,求出每一个子串,之后判断是不是回文,找到最长的那个。

求每一个子串时间复杂度O(N^2), 判断子串是不是回文O(N),两者是相乘关系,所以时间复杂度为O(N^3)。

#include <iostream>
using namespace std;

string longestPalindrome(string &s)
{
    int len = s.size();                  //字符串长度
    int maxlen = 1;                      //最长回文字符串长度
    int start = 0;                       //最长回文字符串起始地址
    for(int i = 0; i < len; i++)         //起始地址
    {
        for(int j = i + 1; j < len; j++) //结束地址
        {
            int tmp1 = i, tmp2 = j;
            while(tmp1 < tmp2 && s.at(tmp1) == s.at(tmp2))//判断是不是回文
            {
                tmp1++;
                tmp2--;
            }

            if(tmp1 >= tmp2 && j - i + 1 > maxlen)
            {
                maxlen = j - i + 1;
                start = i;
            }
        }
    }

    return s.substr(start, maxlen);
}

int main()
{
    string s;
    cout << "Input source string: ";
    cin >> s;
    cout << "The longest palindrome: " << longestPalindrome(s);
    return 0;
}

运行结果:

Input source string: abbacdeedc
The longest palindrome: cdeedc

二、动态规划

设状态dp[j][i]表示索引j到索引i的子串是否是回文串。则转移方程为:

《四种方法求最长回文串》 1.png

则dp[j][i]为true时表示索引j到索引i形成的子串为回文子串,且子串起点索引为j,长度为i – j + 1。
算法时间复杂度为O(N ^ 2)。

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

string longestPalindrome(string s)
{
    const int n = s.size();
    bool dp[n][n];
    memset(dp, 0, sizeof(dp));

    int maxlen = 1;     //保存最长回文子串长度
    int start = 0;      //保存最长回文子串起点
    for(int i = 0; i < n; ++i)
    {
        for(int j = 0; j <= i; ++j)
        {
            if(i - j < 2)
            {
                dp[j][i] = (s[i] == s[j]);
            }
            else
            {
                dp[j][i] = (s[i] == s[j] && dp[j + 1][i - 1]);
            }

            if(dp[j][i] && maxlen < i - j + 1)
            {
                maxlen = i - j + 1;
                start = j;
            }
        }
    }

    return s.substr(start, maxlen);
}

int main()
{
    string s;
    cout << "Input source string: ";
    cin >> s;
    cout << "The longest palindrome: " << longestPalindrome(s);
    return 0;
}

三、中心扩展法

中心扩展就是把给定的字符串的每一个字母当做中心,向两边扩展,这样来找最长的子回文串。算法复杂度为O(N^2)。
需要考虑两种情况:
长度为奇数的回文串,比如a, aba, abcba
长度为偶数的回文串,比如aa, abba

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

string longestPalindrome(string &s)
{
    const int len = s.size();
    int maxlen = 1;
    int start = 0;

    for(int i = 0; i < len; i++)//求长度为奇数的回文串
    {
        int j = i - 1, k = i + 1;
        while(j >= 0 && k < len && s.at(j) == s.at(k))
        {
            if(k - j + 1 > maxlen)
            {
                maxlen = k - j + 1;
                start = j;
            }

            j--;
            k++;
        }
    }

    for(int i = 0; i < len; i++)//求长度为偶数的回文串
    {
        int j = i, k = i + 1;
        while(j >= 0 && k < len && s.at(j) == s.at(k))
        {
            if(k - j + 1 > maxlen)
            {
                maxlen = k - j + 1;
                start = j;
            }

            j--;
            k++;
        }
    }

    return s.substr(start, maxlen);
}


int main()
{
    string s;
    cout << "Input source string: ";
    cin >> s;
    cout << "The longest palindrome: " << longestPalindrome(s);
    return 0;
}

四、Manacher算法

Manacher算法的时间复杂度为O(N),具体可参考:
https://www.cnblogs.com/grandyang/p/4475985.html

更多内容请关注微信公众号

《四种方法求最长回文串》 feicuisenlin_12x12.jpg

    原文作者:海天一树X
    原文地址: https://www.jianshu.com/p/c82cada7e5b0
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞