マナチャーアルゴリズムとその拡張

回文字符串:

  1. 反対を見るときも同じです
  2. abccbaabcbaは軸対称です

最長のパリンドロームストリングの問題

文字列内で最長のパリンドローム文字列を検索します。マナチャーアルゴリズムは、最長のパリンドローム文字列を検索することです。

使用は何ですか?

DNA配列パリンドローム遺伝子配列にはいくつかの生理学的意義があります

最長のパリンドローム問題に対する暴力的な解決策(O(N 2)O(N ^ 2)O N2

ab | abは虚軸に従って対称です

アババは実軸の真ん中の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;
	}

マナチャーアルゴリズムO(N)

特定の情報を保存し、上記のアイデアの拡張プロセスを加速し、必要な情報にアクセスし、線形時間を達成します(kmpと同様)。

ヒントの理解をスピードアップします:
[外部リンク画像の転送に失敗しました。ソースサイトにリーチ防止リンクメカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします(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