最长回文子串

最长回文子串

给定一个字符串 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时,如下图。这种情况,没法利用到回文串的特性,只能老老实实的一步步去匹配。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值