zoukankan      html  css  js  c++  java
  • Manacher算法求解最长回文串

    推荐的参考博文

    根据博主的介绍,我写出了下面的C++代码

    #include<bits/stdc++.h>
    using namespace std;
    
    string Pre(string s)
    {//将s转化成ManacherString 
    	int lenth = s.size();
    	string line="#";
    	for(int i=0;i<lenth;i++)
    	{
    		line+=s[i];
    		line+="#";
    	}
    	return line;
    }
    
    string Manacher(string aim)
    {
    	aim = Pre(aim);//字符串预处理
    	int lenth = aim.size();
    	int* temp = new int[lenth];
    	for(int i=0;i<lenth;i++)temp[i]=1;//初始化回文半径数组 
    	//下面是核心代码
    	int p=0,C=-1,R=-1;//p当前访问字符,C最右回文边界的对称中心,R最右回文边界
    	while(p<lenth)
    	{
    		if(p>R)//要移动的位置p在R的右侧
    		{
    			int s = p;
    			while(s<lenth&&2*p-s>=0&&aim[s]==aim[2*p-s])s++;//以p为中心向两侧扩张
    			C=p;R=s-1;temp[p]=s-p;
    		}
    		else// if(p<=R) 第二种情形:要移动的位置p不在R的右侧
    		{
    			int p2 = 2*C-p;//p2是p1以C为对称中心的对称点
    			int cL = 2*C-R;//cL是以C为对称中心的回文子串的左边界
    			int pL = p2-temp[p2]+1;//pL是以p2为对称中心的回文子串的左边界
                //第二情形的三种情况
                if(cL==pL)
                {
                    int s = R;
    				while(2*p-s>=0&&s<lenth&&aim[s]==aim[2*p-s])s++;
    				C=p;R=s-1;temp[p]=s-p;
                }
                else temp[p] = (cL<pL)? temp[p2]:(R-p+1);
    		}
    		p++;//千万不要忘了这个
    	}//while
        //下面查找答案
    	int maxnum = -1;
    	int maxp=-1;
    	string ans="";//用于存储将要返回的最长回文串
        //下面检测最长回文串的中心
    	for(int i=0;i<lenth;i++)
    	{
    		if(temp[i]>maxnum)
    		{
    			maxnum = temp[i];
    			maxp = i;
    		}
    	}
    	for(int i=maxp-maxnum+1;i<maxp+maxnum;i++)
    	{//整理最长回文串
    		if(aim[i]!='#')ans+=aim[i];
    	}
    	delete[] temp;//删除长度记录数组
    	return ans;
    }
    
    
    int main()
    {
    	string aim = "acbbcbds";
    	cout<<Manacher(aim)<<endl;
    	return 0;
    }//输出的是cbbc
    

    先不要急着抄写,下面我们对核心代码进行压缩并使其模板化


    string Pre(string s)
    {//将s转化成ManacherString 
    	int lenth = s.size();
    	string line="#";
    	for(int i=0;i<lenth;i++)
    	{
    		line+=s[i];
    		line+="#";
    	}
    	return line;
    }
    
    int NormalExtend(int center,int lenth,string& aim,int& C,int& R)
    {//对称中心center,字符串长度lenth,字符串引用aim,最右回文边界的对称中心C,最右回文边界R
    	int s = max(center,R);
    	while(s<lenth && 2*center-s>=0 && aim[s]==aim[2*center-s]) s++;
    	C=center;
    	R=s-1;
    	return s-center;//该值会被赋给标记数组temp[center]
    }
    
    string Manacher(string aim)
    {
    	aim = Pre(aim);//字符串预处理
    	int lenth = aim.size();
    	int* temp = new int[lenth];
    	for(int i=0;i<lenth;i++)temp[i]=1;//初始化回文半径数组
    
    	//下面是核心代码的压缩版本
    	int p=0,C=-1,R=-1;//p当前访问字符,C最右回文边界的对称中心,R最右回文边界
    	while(p<lenth)
    	{
    		int p2 = 2*C-p;//p2是p1以C为对称中心的对称点
    		int cL = 2*C-R;//cL是以C为对称中心的回文子串的左边界
    		int pL = p2-temp[p2]+1;//pL是以p2为对称中心的回文子串的左边界
    		if(p>R || (p<=R&&cL==pL)) temp[p] = NormalExtend(p,lenth,aim,C,R);
    		else temp[p] = (cL<pL)? temp[p2]:(R-p+1);
    		p++;
    	}
    
        //下面查找答案
    	int maxnum = -1;
    	int maxp=-1;
    	string ans="";//用于存储将要返回的最长回文串
        //下面检测最长回文串的中心
    	for(int i=0;i<lenth;i++)
    	{
    		if(temp[i]>maxnum)
    		{
    			maxnum = temp[i];
    			maxp = i;
    		}
    	}
    	for(int i=maxp-maxnum+1;i<maxp+maxnum;i++)
    	{//整理最长回文串
    		if(aim[i]!='#')ans+=aim[i];
    	}
    	delete[] temp;//删除长度记录数组
    	return ans;
    }
    

    OK

  • 相关阅读:
    17点50分系列-如何平静的工作
    Java之简单的聊天工具
    伪分布式环境下命令行正确运行hadoop示例wordcount
    Linux 从 sar 到 sar2html 的认识
    telnet简单操作 模拟请求
    3D跑酷游戏《月影忍者之疾风狂逃》
    [每日一题] OCP1z0-047 :2013-07-24 子查询――外查询与内查询的执行顺序
    思科27亿美元收购网络安全公司Sourcefire
    利用Format函数格式化时间和日期
    HI3531网络tftp、nfs加载 分类: arm-linux-Ubuntu HI3531 2014-01-03 09:11 826人阅读 评论(0) 收藏
  • 原文地址:https://www.cnblogs.com/savennist/p/13392126.html
Copyright © 2011-2022 走看看