Manachar算法(马拉车算法)

什么是回文串,所谓回文串,简单来说就是正着读和反着读都是一样的字符串,比如ababa,abba等等,一个字符串的最长回文子串即为这个字符串的子串中,是回文串的最长的那个。
一种比较常见的算法:枚举长度。时间复杂度的平方级别的
之前写的java代码:

public class 最长回文子串 {
    static int min = 0, max = 0;
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        char[] c = sc.nextLine().toCharArray();
        int n = c.length;
        boolean[][] ok = new boolean[n+1][n+1];
        // 初始化 
        // 长度1
        for(int i=0; i<n; i++)
            ok[i][i] = true;
        // 长度2
        for(int i=0; i+1<n; i++) {
            if(c[i]==c[i+1]) {
                ok[i][i+1] = true;
                min = i;
                max = i+1;
            }
        }
        // 长度3
        for(int i=0; i+2<n; i++) {
            if(c[i] == c[i+2]) {
                ok[i][i+2] = true;
                min = i;
                max = i+2;
            }
        }
        // 长度为4或以上的区间
        for(int k=4; k<=n; k++) {
            for(int i=0; i+k-1<n; i++) {
                int j = i+k-1;
                if(c[i]==c[j] && ok[i+1][j-1]) {
                    ok[i][j] = true;
                    min = i;
                    max = j;
                }
            }
        }
        for(int i=min; i<=max; i++) {
            System.out.print(c[i]);
        }
    }
}

这里介绍一个能够在线性时间求解的算法
博主比较懒而且字比较丑见谅!!!其实博主不会画图…
这里写图片描述
这里写图片描述
c++代码

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

const int maxn = 1000010;
char s[1000010];
char str[1000010<<1];
int len[1000010<<1];
int Min = 0, Max = 0;
int init(char* s){
    int n = strlen(s);
    str[0] = '%';
    for(int i=1; i<=2*n; i+=2){
        str[i] = '#';
        str[i+1] = s[i/2];
    } 
    str[2*n+1] = '#';
    str[2*n+2] = '$'; // 防止越界
    str[2*n+3] = 0;  
    return 2*n+1; 
}
void manachar(char* str, int n){
    int P = 0, ans = 0, po = 0;
    for(int i=1; i<=n; i++){
        if(P>=i){ // 在对称范围内,这一步是优化的关键 
            int j = 2*po-i;
            len[i] = min(len[j], P-i+1);
        }else{    // 不在对称范围内,没有优化 
            len[i] = 1;
        }
        while(str[i-len[i]] == str[i+len[i]]){ // 朴素计算回文,直到找不到回文 
            len[i]++;
        }
        if(len[i]+i-1 > P){ // 更新最远的P和对应的下标po 
            P = len[i]+1-1;
            po = i;
        }
        if(len[i] > ans){
            ans = len[i];
            Min = i-ans+1;
            Max = i+ans-1;
        }
    }
}
int main(){
    // 提升读写速度 
    ios::sync_with_stdio(false);
    cin.tie(0);

    char s[10000];
    cin >> s;
    int n = init(s);
    manachar(str, n);
    for(int i=Min; i<=Max; i++){
        if(str[i]!='#'){
            cout << str[i];
        }
    }
    cout << endl;
}

猜你喜欢

转载自blog.csdn.net/weixin_39778570/article/details/80754410