Manacher's Algorithm(马拉车)

最长回文子串简介:

Longest palindromic substring

相关算法及时间复杂度:

1.暴力求解: O(N!)

2.中心扩展: O(N^2)

3.Manacher's Algorithm:  O(N)

我只解释第三个:

马拉车:(要理解回文的特性)

1.数据结构: 源字符串+一维数组+中心标记符+最右扩展位置标记符+预处理后的字符串

char str[MAXN],newstr[3*MAXN];
int center,righ,p[MAXN*3];

2.预处理字符串:

e.g:

str: a b b a c \rightarrow newstr: *a*b*b*a*c*

newstr[0]='*';
int newlen=0;//预处理字符串之后的长度
for(int i=0;i<len;++i)
{
    newstr[++newlen]=str[i];
    newstr[++newlen]='*';
}

3.预处理标记符:

int center=0,righ=0;

4.算法实现:

for(int i=0;i<newlen;++i)
{
    p[i]=(righ>i)?min(p[2*center-i],righ-i):1;//核心
    while(newstr[i-p[i]]==newstr[i+p[i]])//扩展代码
       ++p[i];
    if((i+p[i])>righ)//更新中心点,最右标记
    {
       righ=i+p[i];
       center=i;
    }
}

算法解释:

1.核心:

现在分为两种情况:

一、i  < righ:

二、i >= righ:

第二种由于没有被以前的 center 包含,所以只能老实扩展 --> while(...) ++p[i];

主要是第一种情况:

一般来说, p[i] 就应该等于 i 关于 center 对称的 2*center-i 的 p,但是这里又要考虑两种情况:

如果p[i]=p[2*center - i]:

一.1: 那么 p[i] + i  可能会超出 righ,而我们又不能保证超出的部分也是合理的,所以,我们要保守估计,那么p[i] <= righ - i;(截掉了超出的部分)

一.2:但是,也有可能不会超出,即 p[i] + i <= righ ,这个时候,就放心大胆地把p [i] = p[2*center - i];

因此:p[i] = min(p[2*center - i],righ-i);

CODE:(以51NOD1088为例)

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
const int MAXN = 1e3+10;
using namespace std;
char str[MAXN];
int p[MAXN],ans;
int main()
{
        cin>>str;
        char newstr[MAXN*3];
        ans=1;
        int len=strlen(str);
        int center=0,righ=0;
        newstr[0]='#';
        int newlen=0;
        for(int i=0;i<len;++i)
        {
            newstr[++newlen]=str[i];
            newstr[++newlen]='#';
        } 
        for(int i=0;i<newlen;++i)
            p[i]=1;
        for(int i=0;i<newlen;++i)
        {
            p[i]=(righ>i)?min(p[2*center-i],righ-i):1;
            while(newstr[i-p[i]]==newstr[i+p[i]])
                ++p[i];
            if((i+p[i])>righ)
            {
                righ=i+p[i];
                center=i;
            }
            ans=max(ans,p[i]-1);
        } 
        cout<<ans<<endl;
}
/*
daabaac
*/

 

马拉车算法是一种常用于字符串匹配的算法,其核心思想是利用回文串的对称性来减少比较次数。Java中可以通过以下步骤实现马拉车算法: 1. 预处理字符串,将字符串中的每个字符用一个特殊字符隔开,如:将字符串"abc"变成"#a#b#c#" 2. 维护一个数组P,其中P[i]表示以i为中心的最长回文子串的半径长度。具体实现时,可以使用一个中心点center和右边界right来维护,其中center表示当前已知的最长回文子串的中心点,right表示该回文子串的右边界。根据回文串的对称性,可以利用已知回文串的左侧字符的对称点来推出右侧字符的回文半径。 3. 遍历字符串,根据P数组更新center和right,并记录最长回文子串的起始位置和长度。 以下是Java代码实现示例: ```java public class ManacherAlgorithm { public static String longestPalindrome(String s) { if (s == null || s.length() == 0) { return ""; } StringBuilder sb = new StringBuilder(); sb.append("#"); for (int i = 0; i < s.length(); i++) { sb.append(s.charAt(i)); sb.append("#"); } String str = sb.toString(); int[] P = new int[str.length()]; int center = 0, right = 0; int start = 0, maxLen = 0; for (int i = 0; i < str.length(); i++) { if (i < right) { P[i] = Math.min(right - i, P[2 * center - i]); } while (i - P[i] - 1 >= 0 && i + P[i] + 1 < str.length() && str.charAt(i - P[i] - 1) == str.charAt(i + P[i] + 1)) { P[i]++; } if (i + P[i] > right) { center = i; right = i + P[i]; } if (P[i] > maxLen) { start = (i - P[i]) / 2; maxLen = P[i]; } } return s.substring(start, start + maxLen); } public static void main(String[] args) { String s = "babad"; System.out.println(longestPalindrome(s)); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值