最长回文字符串常用求法

 最长回文字符串常用求法一般有以下几种:

1 暴力求解

先给出每个字串s[i...j],i=0...len,j=i,...len,其时间复杂度O(N^2),再针对每个字串判断是否是回文需要时间O(N),故该算法时间复杂度O(N^3),空间复杂度O(1)。

#define max 100+10
char buf[max*2];
char tmp[max*2];
void get_longest_str(){
printf("请输入字符串\n");
fgets(buf,max,stdin);//fgets输入,遇见换行才停
int len=strlen(buf);
int i,j=0;
int p[max*2]={0};//pi存储的是tmpi在Buf位置
for(i=0;i<len;i++)
    if(isalpha(buf[i])){tmp[j]=toupper(buf[i]);p[j]=i;j++;}//tmp存的都是大写字母
int s_len=j;
int max_len=0;
int ii,jj;
printf("%s\n",tmp);
for(i=0;i<s_len;i++)//  for each element in string
    for(j=i;j<s_len;j++)//start at i
      {//判断s[i..j]是一个回文串
	  bool f=1;
	  for(int k=i;k<=j;k++)
	      if(tmp[k]!=tmp[i+j-k])f=0;
	  if(f&&j-i+1>max_len){max_len=j-i+1;ii=i;jj=j;}
      }
printf("最大回文长度:%d\n",max_len);
for(i=p[ii];i<=p[jj];i++)
    printf("%c",buf[i]);
printf("\n");
}

2 动态规划

动态规划是暴力解法的改进,引入二维数组p[i][j],p[i][j]=1表示字串s[i]到s[j]是回文故由动态规划思想:

初始:

p[i][j]=1, if j=i

p[i][j]=1,if j=i+1&&s[i]=s[i+1]

动态:

p[i][j]=1,if s[i]=s[j]&&p[i+1][j-1]=1

故不同于暴力求解,针对每个字串,只需判断p[i][j]=1即可,时间复杂度O(1),总体而言,时间复杂度O(N^2),空间复杂度O(N^2)

void get_longest_str_update(){
printf("请输入字符串:\n");
fgets(buf,max,stdin);
int len=strlen(buf);
int i,j=0;
int p[max*2]={0};
for(i=0;i<len;i++)
    if(isalpha(buf[i])){tmp[j]=toupper(buf[i]);p[j]=i;j++;}
int s_len=j;
int max_len=0;int ii,jj;
//动态规划
bool table[max][max]={0};
for(i=0;i<s_len;i++)
    table[i][i]=1;
for(i=0;i<s_len-1;i++)
    if(tmp[i]==tmp[i+1]){table[i][i+1]=1;max_len=2;ii=i;jj=i+1;}
//以上两个for为初始化
for(int l=3;l<=s_len;l++)//字串长度
   for(i=0;i<=s_len-l;i++)//字串起始位置
   {
       j=i+l-1;//l=j-i+1
       if(table[i+1][j-1]==1&&tmp[i]==tmp[j])
       {table[i][j]=1;max_len=l;ii=i;jj=j;
       }
   }
printf("最大回文长度:%d\n",max_len);
for(i=p[ii];i<=p[jj];i++)
    printf("%c",buf[i]);
printf("\n");
}

3 中心扩展

中心扩展就是把给定的字符串的每一个字母当做中心,向两边扩展,这样来找最长的子回文串。算法复杂度为O(N^2)。唯一需要注意的是字串长度为奇数和偶数分开讨论。

void get_longest_str_expand(){
printf("请输入字符串:\n");
fgets(buf,max,stdin);
int len=strlen(buf);
int i,j=0,k;
int p[max*2]={0};
for(i=0;i<len;i++)
    if(isalpha(buf[i])){tmp[j]=toupper(buf[i]);p[j]=i;j++;}
int s_len=j;
int max_len=0;int ii,jj;
for(i=0;i<s_len;i++)
{j=i-1;k=i+1;
    while(j>=0&&k<s_len&&tmp[j]==tmp[k]){
	if(k-j+1>max_len){
	max_len=k-j+1;ii=j;jj=k;}
	j--;k++;//以i为中心向两边散开
                                        }
}//长度为奇数
for(i=0;i<s_len;i++)
{j=i;k=i+1;
    while(j>=0&&k<s_len&&tmp[j]==tmp[k]){
	if(k-j+1>max_len){
	    max_len=k-j+1;ii=j;jj=k;
	                  }
	j--;k++;
                                         }
}
printf("最大回文长度:%d\n",max_len);
for(i=p[ii];i<=p[jj];i++)
    printf("%c",buf[i]);
printf("\n");

}



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值