Manacher算法及其扩展

回文字符串:

  1. 正着看反着看是一样的
  2. abccba abcba 存在一个轴对称

最长回文字符串问题

在一个字符串中找到最长回文字符串,而manacher算法就是去找这个最长回文字符串。

有啥用?

DNA序列 回文基因序列有一些生理学意义

暴力解最长回文问题( O ( N 2 ) O(N^2) O(N2)

ab|ab 按照虚轴对称

ababa 按照实轴中间的a对称

遍历每个实轴与虚轴,分别向两边扩展,存最长的

public static String getmaxstr(String s)
	
	{
    
    
		int maxlength=0;
		String  maxstr="";
		//从每一个轴扩展 包含实轴(是一个数,找奇数最长回文字符串)  和虚轴(找偶数最长回文字符串)
		for(int i=0;i<s.length();i++)
		{
    
    
			
			//以该字母为实轴
			int m=i;
			int n=i;
		
			while(m>=0&&n<s.length()&&s.charAt(m)==s.charAt(n))
			{
    
    
				if(n-m+1>maxlength)
				{
    
    
					maxlength=n-m+1;
					maxstr=s.substring(m, n+1);
				}
				m-=1;
				n+=1;
			}
			
			
			//以该字母后面为虚轴
			 m=i;
			 n=i+1;
			 
			 while(m>=0&&n<s.length()&&s.charAt(m)==s.charAt(n))
				{
    
    
					if(n-m+1>maxlength)
					{
    
    
#### #### 						maxlength=n-m+1;
						maxstr=s.substring(m, n+1);
					}
					m-=1;
					n+=1;
				}
		}
		return maxstr;
	}

Manacher算法O(N)

其存储一定信息,加速上述思路的扩展过程,存取必要信息,达到线性时间(与kmp类似哈)

加速tips的理解:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jYHbfN17-1610177620001)(6D1F901ACFFE4D52A3ECC159C8ADEEA5)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kB0WQFAW-1610177620004)(6D43EE153741447C8DCA2A0F5A34C049)]
在这里插入图片描述

存储的信息

  1. 回文半径数组(以每一位为中心的回文字符串长度)
  2. r(最远的右边界)
  3. c(最远的右边界的中心点)

几种情况

  1. i在r外的时候 没有任何优化
  2. i在r内的时候 若镜面无法完全包含,我们直接跳到镜面外的字母开始更新就行
  3. i在r内的时候 若镜面完全包含,我们没必要拓展这个字母

代码

	//tested
	//abcd->#a#b#c#d#
	public static char[] tostrx(String str)
	{
    
    
		char[] strx=new char[2*str.length()+1];
		int l=0;
		for(int i=0;i<strx.length;i++)
		{
    
    
			if(i%2==0)
			{
    
    
				strx[i]='#';
			}
			else {
    
    
				strx[i]=str.charAt(l);
				l+=1;
			}
		}
		return strx;
	}
	
	
	//tested
	//检测i是否在数组x(长度为l)越界
	public static boolean isvalid(int i,int l)
	{
    
    
		if(i>=0&&i<l)
			return true;
		return false;
	}
	
	
	
	
	
	
	//tested
	//返回该节点的最大回文字符串长度
	public static int expand(char[] strx,int i,int j)//以i节点为中心,从j节点开始扩展
	{
    
    
		while(isvalid(j, strx.length)&&isvalid(2*i-j,strx.length)&&strx[j]==strx[2*i-j])
		{
    
    
			j+=1;
		}
		j-=1;
		return 2*(j-i)+1;
		
	}
	
	
	//tested
	//得到最大回文字符串(去掉#)
	public static String str(char[] t,int[] parax)
	{
    
    
		int maxi=-1;
		int max=-1;
		for(int i=0;i<parax.length;i++)
		{
    
    
			if(parax[i]>max&&!(i%2==0&&parax[i]==1))
			{
    
    
				max=parax[i];
				maxi=i;
			}
		}
		String str=tostr(t, maxi-(max-1)/2, maxi+(max-1)/2);
		return str;
	}
	
	
	
	//manacher算法
	public static String manacher(String str)
	{
    
    
		char[] strx=tostrx(str);
		int[] parax=new int[strx.length];//存取每一位的回文字符串的最大长度
		int c=-1;
		int r=-1;//存取最远右边界
		
		for(int i=0;i<strx.length;i++)
		{
    
    
			if(i<r)
			{
    
    
				//parax[2*c-i]-1)/2+i  由镜像节点得到当前节点的右边界
				if((parax[2*c-i]-1)/2+i<r)//在镜面内
				{
    
    
					parax[i]=parax[2*c-i];
				}
				else {
    
    
					parax[i]=expand(strx, i,r);
				}
				
			}
			else {
    
    
				parax[i]=expand(strx, i, i+1);
			}
		}
		
		String string=str(strx,parax);
		
		return string;
		
		
	}
	
	//tested
	//给定#a#b#c#d#  第几位到第几位  截取并删除#
	public static String tostr(char[] strx,int a,int b)
	{
    
    
		String str="";
		for(int i=a;i<=b;i++)
		{
    
    
			if(i%2!=0)
			{
    
    
				str=str+strx[i];
			
			}
		}
		return str;
	}

猜你喜欢

转载自blog.csdn.net/hch977/article/details/112392513