zoukankan      html  css  js  c++  java
  • 【模板】manacher算法

    看进阶指南的时候看到的算法,正好最近没啥事干来学一下

    大致题意

    给一个长度为(n)字符串(S),求(S)中的最长回文字串

    (n≤1.1×10^7)


    分析

    算法一

    暴力

    枚举每个点能扩散到的最大长度

    时间复杂度(O(n^2))


    算法二

    (hash+)二分

    建立出(S)的前后缀(hash)值,然后二分答案,找到最大扩展长度

    时间复杂度(O(nlogn))


    算法三

    (manacher)麻辣串算法

    算法流程

    1.在每两个字符间插入一个额外字符,以去掉偶回文串的情况


    2.定义(r_i)表示以(i)为中心时的最大回文半径

    (R)表示当前情况能扩展到的最右字符((即最右回文右端点)),(mid)表示最右回文的中心

    考虑每个新进来的字符的情况:

    (1.) (i∈[mid,R])

    显然,(i)有一个关于(mid)的对称点(j = mid×2-i),根据对称性,(j)周围的字符和(i)周围的字符一定相同,于是可以先用(r_j)去更新(r_i),即(r_i = min(r_{mid×2-i},r_{mid}-i+mid)),(右侧不能大于(R),否则处于未知的位置,无法保证正确性),最后再去试试(i)还能不能扩展,同时更新(R)(mid)的值

    (2.) (i∈(R,n])

    此时(i)处于一个未知的位置,因此只能暴力扩展,同时更新(R)(mid)的值

    最后的答案即为((2*max(r_i)-2)/2 = max(r_i)-1),由于(R)最多会向右移(n)次,因此总时间复杂度为线性((O(n)))

    (code)

    #include<bits/stdc++.h>
    using namespace std;
    const int MAXN = 91000000;
    char c[MAXN];
    char s[MAXN];
    int L[MAXN],R[MAXN]; 
    int MAX_R;
    int r[MAXN],len,mid; 
    void manacher(){
    	for(int i=1;i<len;i++){
    		if(MAX_R>i&&mid<=i) r[i] = min(r[mid*2-i],r[mid]-i+mid);
    		else r[i] = 1;
    		while(s[i+r[i]]==s[i-r[i]]) r[i]++;
    		if(i+r[i]>MAX_R){
    			mid = i;
    			MAX_R = r[i]+i;	
    		}
    	}
    }
    int main(){
    	cin>>c;
    	s[0] ='#',s[1] = '#';
    	len = strlen(c); 
    	for(int i=0;i<len;i++){
    		s[i*2+2] = c[i];
    		s[i*2+3] = '#';
    	} 
    	len = len*2+2;
    	int ans = -114514;
    	manacher();
    	for(int i=0;i<len;i++){
    		ans = max(ans,r[i]);
    	}
    	cout<<ans-1;
    } 
    
  • 相关阅读:
    SpringBoot之集成Socket
    SpringBoot之集成WebSocket
    SpringBoot之统一异常处理
    请求的转发和重定向
    5+App使用定位
    将Tomcat注册为Windows服务
    Tomcat环境变量设置
    CentOS7搭建Gitlab详细过程
    Python 12 内置函数
    Python 11 生成器
  • 原文地址:https://www.cnblogs.com/xcxc82/p/13866825.html
Copyright © 2011-2022 走看看