zoukankan      html  css  js  c++  java
  • [学习笔记]马拉车-Manacher

    [学习笔记]马拉车-Manacher

    一.概念

    ​ 在日常做题中,经常会遇到求回文串的问题,而马拉车算法可以在 (O(n)) 的时间中求出一个字符串的最大回文子串。顺带一提,这个算法是音译。然后挂一下模板链接

    二.基本思想

    ​ 首先对于以下两个串 (aabaa)(aabbaa) 很显然它们整个都是回文的,但是如果要寻找一个所谓的“中心”,第一个串好找,第二个则说不清。然后马拉车的一个奇妙策略是插空,即在字母与字母间插入一个“隔板”,这里我用的'|',于是两个串就变为了(|a|a|b|a|a|)(|a|a|b|b|a|a|),

    ​ 把插进去的隔板计算在内的话,则第一个串的”中心“是'b',第二个串的”中心“是'|',这种策略使串都成了奇数长度,于是方便找中心。

    ​ 此时引入两个变量,(p[i])表示以i为中心的最大回文串的半径,(mid,mx)则分别表示当前已知的最长回文串的中心与右端点。,那么对于一个扫描到的新点 i 。有多种情况。

    ​ case 1:它在已知的右端点内。那么相关于中心,(有点平面镜成像的感觉?也有可能是数轴?),i 有个对称点 j,由对称点公式易得(初一数学奥),(j=2*mid-i).那么 j 有 一个已知的 p[j],由于(mid*2-mx——mx)是回文串,理想情况下可以令 p[i]=p[j] 但是实际上有可能i+p[i] 延伸到了 mx 的右边,此时无法根据 mx 的回文串性质直接相等,那么限制一下使 (p[i]=min(p[(mid<<1)-i],mx-i+1)) 就好。当然这还没完,需要手动探测一下两边(看代码就很清楚)

    ​ case 2:不在右端点内,直接手动探测奥。

    最后注意维护一下mx与mid就好。由于mx一直是一直增加的,i也是由1~n,所以是(O(n))

    三.CODE(模板)

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<fstream>
    using namespace std;
    const int MAXN=1.1*1e7;
    char ch[MAXN*2];
    int mid,mx,tot,p[2*MAXN],ans;
    void read(){
    	char c=getchar();
    	ch[0]='~';ch[(tot=1)]='|';
    	while(c<'a'||c>'z')c=getchar();
    	while('a'<=c&&c<='z'){
    		ch[++tot]=c,ch[++tot]='|';
    		c=getchar();
    	}
    }
    int main(){
    	read();
    	for(int i=1;i<=tot;++i){
    		if(i<=mx)p[i]=min(p[(mid<<1)-i],mx-i+1);
    		while(ch[i-p[i]]==ch[i+p[i]])++p[i];
    		if(i+p[i]>mx)mx=i+p[i]-1,mid=i;
    		if(p[i]>ans)ans=p[i];
    	}
    	cout<<ans-1;
    	return 0;
    }
    
  • 相关阅读:
    好记性不如烂笔杆android学习笔记<十四> EditText 画行,解决光标压线问题
    好记性不如烂笔杆android学习笔记<十五> GridView简单用法
    分享个好玩的算法游戏
    ubuntu环境下lnmp环境搭建(3)之Php
    数据可视化之美之疾病潜在关联
    ubuntu环境下lnmp环境搭建(2)之Nginx
    乐观锁和悲观锁
    表单无刷新上传图片
    ubuntu环境下lnmp环境搭建(1)之Mysql
    祭旗篇关于提高技术团队技术氛围的一些尝试
  • 原文地址:https://www.cnblogs.com/clockwhite/p/13381920.html
Copyright © 2011-2022 走看看