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

  • 相关阅读:
    shell 脚本语法
    discuz pre_forum_postposition表说明
    PHP调试工具Xdebug安装配置教程
    检查用户头像状态的脚本
    PHP 性能监测
    Mysql 索引优化
    MySQL主从复制配置
    vue mixin 混入
    vue渲染方式:render和template的区别
    vue自定义指令directive Vue.directive() directives
  • 原文地址:https://www.cnblogs.com/savennist/p/13392126.html
Copyright © 2011-2022 走看看