記事ディレクトリ
回文字符串:
- 反対を見るときも同じです
- 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と同様)。
ヒントの理解をスピードアップします:
保存された情報
- パリンドローム半径配列(各ビットを中心としたパリンドロームストリングの長さ)
- r(最も右の境界)
- c(右端の境界の中心点)
いくつかの状況
- iがrの外側にある場合は最適化されません
- iがrにあるときに、鏡面を完全に封じ込めることができない場合は、鏡面の外側の文字にジャンプして更新を開始します。
- 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&¶x[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;
}