马拉车 回文串 区间dp

一个比较详细的博客https://www.cnblogs.com/love-yh/p/7072161.html

马拉车思想中感觉有点dp,还是觉得每次对每一个中心点计算太麻烦,耗时,所以想让已有的数据对对计算提供帮助。这里面利用了回文字符串的特点,回文。

具体的介绍我也不可能写的有那个博客好,我补充一下代码实现,其他你们去看博客就好了。

牛客题https://ac.nowcoder.com/acm/problem/14517,来试试吧!

当然下面的代码过不了这道题,需要在主函数哪里修改一下!| ^ _^|

具体代码:

#include<cstdio>
#include<iostream>
#include<string>
using namespace std;string st;//加工后的字符串储存位置
char ch[2000];//未加工字符串储存位置 ,也可以使用string取代
int num[2000];//记录每个中心点对称半径的位置,可使用vector替代 
int min(int x,int y){//出较小值,可以用库函数math取代 
return x>y?y:x;}
int gai(){//对字符串进行转制,每个字符间添加#,可以是其他的,但是首尾必须和其他字符不同 	
 	int i=0;
   	st+='$';
   	st+='#';
   	for(int i=0;ch[i]!='\0';i++){
   		st+=ch[i];
   		st+='#';
   	}
 	st+='\0';
   	return 0;
   }
int chu(){
	int len=0,right=0;//len是中心点下标,right是len对称的最后一个字符的下标
	num[0]=0;//第一个为零,添加的是$,纪录的对称半径不包括中心点,为了对应原始字符串的对称长度
	int max=0;//最大值 
	for(int i=1;i!=st.size();i++){
		num[i]=i<right?min(num[len*2-i],right-len):0;
		while(st[i+num[i]+1]==st[i-num[i]-1])num[i]++;//第三种情况 
		if(num[i]>right-len){//更新数值
			len=i;	
			right=i+num[i];
			max=num[i];
		}
	}
	return max;//传递最大数,也可以得到最大串是哪个,我们有中心点和半径 
	}
int main(){
	scanf("%s",ch);
	gai();
	int a=chu();
	printf("the first long words is long %d.\n",a);//输出 
	return 0;
}

自我感觉如果字符串不是很长,对称部分也不长的话,马拉车的算法复杂度接近n的平方,甚至耗时更长。倒叙求法和原始未优化的的算法还是要学会实现比较好。
但是对于求解最长字符串的问题,不只是马拉车,还有一种方法,也可以做到,那就是dp,具体哪一种方法更有,自己体会吧!
dp使用的思想也是利用已经计算过的数据,为下次计算提供方便,其中的状态转移方程是dp[i][j]={dp[i+1][j-1] ch[i]==ch[j]; 0 ch[i]!=ch[j]}其中dp[i][j]的意思是区间i到j是否为回文串,是的话为1,不是为0,也可以让等与回文串长度,这种方法的复杂度为n方。

#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
using namespace std;
string s;//接收字符串
 int dp[1000][1000];//储存
  int main(){	
  	cin>>s;
  	int len=s.size(),ans=1;
  	memset(dp,0,sizeof(dp));//初始化 
  	for(int i=0;i<len;i++){//让长度为一和二的提前算出,作为基础 
  	dp[i][i]=1;
  	if(i<len-1&&s[i]==s[i+1]){
  	dp[i][i+1]=1;	
  	ans=2;
  	}
  	}
  	for(int lon=2;lon<len;lon++){
  		for(int i=0;i+lon<len;i++){
  			if(s[i]==s[i+lon]&&dp[i+1][i+lon-1]==1){
  			dp[i][i+lon]=dp[i+1][i+lon-1];//区间转移,不需要赋值0是因为初始化都为零
  			ans=lon+1;//不需要比大小是因为我们是从小到大计算是否是回问串的,所以后来的一定比开始的长
  			}
  		}
  	}
  	printf("%d\n",ans);//输出最长长度,也可以标点记录位置 
  	return 0; 
  }

其中代码是来自算法笔记中的动态规划,复杂度为n^2。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值