欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

最长回文子串

程序员文章站 2022-07-13 21:58:44
...

最长回文子串

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例 1:
输入: “babad”
输出: “bab”
注意: “aba” 也是一个有效答案。
示例 2:
输入: “cbbd”
输出: “bb”
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-palindromic-substring
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
最长回文子串

解法 4: 扩展中心

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

class Solution {
public:
    string myStr;
    Solution(string str) : myStr(str) {};
    string longestPalindrome() {
        cout << "myStr: " << myStr << endl;
        if ( myStr.empty() ) cout << "empty" << endl;
        int start = 0, end= 0;
        for (int i = 0; i < myStr.size(); ++i) {
            int len1 = expandAroundCenter(myStr, i, i);
            int len2 = expandAroundCenter(myStr, i, i + 1);
            int len = max(len1, len2);
            if (len > end - start) {
                start = i - (len - 1) / 2;
                end = i + len /2;
            }
        }
        string result;
        for (int i = start; i <= end; ++i) {
            result += myStr[i];
        }
        return result;
    }
    int expandAroundCenter(string s, int left, int right) {
        int L = left, R = right;
        while (L >= 0 && R < s.size() && s.at(L) == s.at(R)) {
            --L;
            ++R;
        }
        return R - L -1;
    }
};

int main() {
    string str1;
    cout << "intput str1: " << endl;
    cin >> str1;
    Solution sl1(str1);
    string result = sl1.longestPalindrome();
    cout << "result: " << result << endl;
}

解法 5: Manacher’s Algorithm 马拉车算法。

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

class Solution {
public:
    string Str;
    Solution(string str) : Str(str) {};
    // 马拉车算法
    string longestPalindrome() {
        cout << "Str: " << Str << endl;
        string myStr = preProcess(Str);
        cout << "myStr: " << myStr << endl;
        int n = myStr.size();
        vector<int> P(n,0);
        int C = 0, R = 0; //center, edge Of right
        int maxLen = 0, centerIndex =0;
        for (int i = 1; i < n -1; ++i) {
            int i_mirror = 2 * C - i;
            cout << "i: " << i << " ";
            cout << "i_mirror: " << i_mirror << endl;
            //P[i] = R > i ? min(R - i, P[i_mirror]) : 0;
            if (i < R) {
                //P[i] = min(R - i, P.at(i_mirror));
                if(P.at(i_mirror) < R-i) {
                    P.at(i) = P.at(i_mirror);
                } else {
                    P.at(i) = R -i;
                }            
            } else {
                P.at(i) = 0;
            }
            
            cout << "P.at(" << i << "):" << P[i] << endl;
            // 碰到之前讲的三种情况时候,需要利用中心扩展法
            while(myStr.at(i - P[i] -1) == myStr.at(i + P[i] +1)) {     //not longest
                ++P[i];
            }

            // 判断是否需要更新 R
            if (R < i + P[i]) {  //edge Of right over R
                C = i;
                R = i + P[i];
            }

            if (maxLen < P[i]) {
                maxLen = P[i];
                centerIndex = i;
            }
            
        }
        int start = (centerIndex - maxLen) / 2;
        return Str.substr(start,start + maxLen);
    }
private:
    string preProcess(string s) {
        if (s.empty()) {
            cout << "empty: " << endl;
            return "^$";
        }
        string ret("^");
        for (auto& elem : s) {
            ret += "#";
            ret += elem;
        }
        ret += "$";
        return ret;
    }
};

string preProcess(string s);

int main() {
    string str1("baba");
    cout << "Input a string" << endl;
    cin >> str1;
    Solution sl1(str1);
    string result = sl1.longestPalindrome();
    cout << "result: " << result << endl;
}

参考说明 https://www.cnblogs.com/love-yh/p/7072161.html
引用参考原作者:
昵称: BraveWg
最长回文子串

三)如何求数组P [ ]
从左往右计算数组P[ ], Mi为之前取得最大回文串的中心位置,而R是最大回文串能到达的最右端的值。
1)当 i <=R时,如何计算 P[ i ]的值了?毫无疑问的是数组P中点 i 之前点对应的值都已经计算出来了。利用回文串的特性,我们找到点 i 关于 Mi 的对称点 j ,其值为 j= 2*Mi-i 。因,点 j 、i 在以Mi 为中心的最大回文串的范围内([L ,R]),
a)那么如果P[j] <R-i (同样是L和j 之间的距离),说明,以点 j 为中心的回文串没有超出范围[L ,R],由回文串的特性可知,从左右两端向Mi遍历,两端对应的字符都是相等的。所以P[ j ]=P[ i ](这里得先从点j转到点i 的情况),如下图:
最长回文子串
b)如果P[ j ]>=R-i (即 j 为中心的回文串的最左端超过 L),如下图所示。即,以点 j为中心的最大回文串的范围已经超出了范围[L ,R] ,这种情况,等式P[ j ]=P[ i ]还成立吗?显然不总是成立的!因,以点 j 为中心的回文串的最左端超过L,那么在[ L, j ]之间的字符肯定能在( j, Mi ]找到相等的,由回文串的特性可知,P[ i ] 至少等于R- i,至于是否大于R-i(图中红色的部分),我们还要从R+1开始一一的匹配,直达失配为止,从而更新R和对应的Mi以及P[ i ]。
最长回文子串
2)当 i > R时,如下图。这种情况,没法利用到回文串的特性,只能老老实实的一步步去匹配。
最长回文子串

相关标签: c++