最常回文串和最长回文序列

来源:互联网 发布:优化交通组织工作 编辑:程序博客网 时间:2024/06/08 12:44

最长回文串

两种方法

一种是使用动态规划的,这里的动态规划和最长公共子序列类似,但是计算表格的时候只要计算一般,而且是按照对角线来推进的

void subPalindrome2(char *A,char *sub){int len=strlen(A);int i=0,j=0,sublen;int maxsublen=1;memset(hp,0,N*N*sizeof(char));//初始化sublen=1,2的情况for(i=0;i<len;i++)hp[i][i]='T';for(i=1;i<len;i++){if(A[i-1]==A[i]){maxsublen=2;hp[i-1][i]='T';}elsehp[i-1][i]='F';}//规划sublen>2for(sublen=3;sublen<=len;sublen++){for(i=0,j=sublen-1;j<len;i++,j++){if(A[i]==A[j]){hp[i][j]=hp[i+1][j-1];if(hp[i+1][j-1]=='T')maxsublen=sublen;}elsehp[i][j]='F';}}for(i=0;i<len;i++){for(j=0;j<len;j++)printf("%c ",hp[i][j]);printf("\n");}//找出最大字串for(i=0,j=maxsublen-1;j<len;i++,j++){if(hp[i][j]=='T')break;}for(int k=i;k<=j;k++)sub[k-i]=A[k];}

第二种方法是Manacher算法

void Manacher(char *st,char* sub){//创建临时的字符串int len=strlen(st);char* T=(char*)calloc(len*2+3,sizeof(char));T[0]='@';T[2*len+2]='$';//防止首尾越界int i,maxid=0;for(i=1;i<=len*2;i+=2){T[i]='#';T[i+1]=st[i/2];}T[2*len+1]='#';//建立回文半径数组(包括回文中心)int* R=(int*)calloc(len*2+2,sizeof(int));R[0]=0;int P=0,P0=0;for(i=1;i<=2*len+1;i++){if(i<P)R[i]=min(P-i,R[2*P0-i]-1);elseR[i]=1;while(T[i+R[i]]==T[i-R[i]])R[i]++;if(i+R[i]-1>P){P=i+R[i]-1;P0=i;}if(R[maxid]<R[i])maxid=i;}//提取回文子串int k;for(k=0,i=maxid-R[maxid]+1;i<maxid+R[maxid]-1;i++)if(T[i]!='#')sub[k++]=T[i];sub[k]='\0';free(R);free(T);}


Manacher python实现

#coding:UTF-8__author__ = 'LQ'def manacher(st):    st='@'+st+'$'    T='#'.join(st)#T是转换过的数组    (P,P0,id)=(0,0,0)#P0是最远回文半径对应的中心,P是对应的最远回文半径,id是最大回文半径对应的中心,                      #回文半径包含中心点,下标从1开始,下标i对应的回文串为[i-(R[i]-1),i+(R[i]-1)]    R=[0]#用来保存回文半径    for i in range(1,len(T)-1):        if i<P:            r=min(P-i,R[2*P0-i]-1)        else:            r=1        while T[i+r]==T[i-r]:r+=1        R.append(r)        (P0,P)=(i,r+i-1) if r+i-1>P else (P0,P)        id=id if R[id]>r else i    #输出回文串    sub=T[id-(R[id]-1):id+(R[id])]    sub=sub.replace('#','')    return subif __name__=="__main__":    print manacher('BBABCCBCAB')


最长子序列的思想和上面字符串的思想类似,,也是动态规划

//最长回文子序列void LPS(char *st,char* sub){memset(hp,0,N*N*sizeof(char));int len=strlen(st);int i,j;for(i=0;i<len;i++){hp[i][i]=1;dir[i][i]='o';//表示起点}int sublen;//动态规划长度大于2的字串,这里注意,对于i>j的串我们已经把hp[i][j]=0,所以计算sublen=2可以统一到下面的循环for(sublen=2;sublen<=len;sublen++){for(i=0;i<len-sublen+1;i++){j=i+sublen-1;if(st[i]==st[j]){dir[i][j]='+';hp[i][j]=hp[i+1][j-1]+2;}else{if(hp[i][j-1]>hp[i+1][j]){hp[i][j]=hp[i][j-1];dir[i][j]='R';}else{hp[i][j]=hp[i+1][j];dir[i][j]='U';}}//这里注意起点可能也是"aa"这样的串!!!if(sublen==2)dir[i][j]='o';}}//for(i=0;i<len;i++)//{//for(j=0;j<len;j++)//printf("%c ",dir[i][j]);//printf("\n");//}//printf("%d\n",hp[0][len-1]); //回溯出最长回文串i=0,j=len-1;int pbeg=0,pend=hp[0][len-1]-1;while(dir[i][j]!='o'){if(dir[i][j]=='+'){sub[pbeg++]=sub[pend--]=st[i];i++,j--;}if(dir[i][j]=='U')i++;if(dir[i][j]=='R')j--;}sub[pbeg]=sub[pend]=st[i];//如果起点是一个字符pbeg=pend,如果是两个字符则不相等}




0 0
原创粉丝点击