洛谷p2957

该博客讨论了一种算法问题,涉及寻找两个字符串之间的最长重复部分。文章提供了两种解决方案,一种是暴力枚举字符串回声长度并比较,另一种是使用哈希技巧快速判断前缀和后缀的匹配。通过示例解释了问题,并给出了C++实现代码。
摘要由CSDN通过智能技术生成

奶牛们非常享受在牛栏中哞叫,因为她们可以听到她们哞声的回音。虽然有时候并不能完全听到完整的回音。Bessie曾经是一个出色的秘书,所以她精确地纪录了所有的哞叫声及其回声。她很好奇到底两个声音的重复部份有多长。

输入两个字符串(长度为1到80个字母),表示两个哞叫声。你要确定最长的重复部份的长度。两个字符串的重复部份指的是同时是一个字符串的前缀和另一个字符串的后缀的字符串。

我们通过一个例子来理解题目。考虑下面的两个哞声:

moyooyoxyzooo

yzoooqyasdfljkamo

第一个串的最后的部份"yzooo"跟第二个串的第一部份重复。第二个串的最后的部份"mo"跟第一个串的第一部份重复。所以"yzooo"跟"mo"都是这2个串的重复部份。其中,"yzooo"比较长,所以最长的重复部份的长度就是5。

输入格式

* Lines 1..2: Each line has the text of a moo or its echo

输出格式

* Line 1: A single line with a single integer that is the length of the longest overlap between the front of one string and end of the other.

输入输出样例

输入 #1复制

abcxxxxabcxabcd 
abcdxabcxxxxabcx 

输出 #1复制

11 

说明/提示

'abcxxxxabcx' is a prefix of the first string and a suffix of the second string.

substr

a=s.substr(n,m):截取字符串 ss 中从第 n位(位数从 0开始)开始的长度为 m 的字符串并赋给 a。

s.find(n):返回字符串 n在 s 中第一次出现的位置(开头),如果没有找到,则返回 -1。

因为数据范围极小,所以直接枚举回声的长度暴力判断即可。

#include<bits/stdc++.h>
using namespace std;
string a,b;
int main(){
	cin>>a>>b; if(a.size()>b.size())swap(a,b);//如果a比b长,先调换位置,避免substr时访问越界
	for(int x=a.size()-1;x>=0;x--){//x代表回声的长度
		string prea=a.substr(0,x),sufa=a.substr(a.size()-x,x);
		string preb=b.substr(0,x),sufb=b.substr(b.size()-x,x);
		if(prea==sufb||preb==sufa)cout<<x<<endl,exit(0);
		//如果一个字符串的前缀等于另一个字符串的后缀,输出答案即可
	} return 0;
}

hash

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<climits>
#include<cmath>

using namespace std;
const int N=110,base=131;
typedef unsigned long long ULL;
ULL p[N],hl[N],hr[N];
char stra[N],strb[N];
int lena,lenb,lmax;

ULL get(ULL h[],int l,int r)
{
	return h[r]-h[l-1]*p[r-l+1];
}//求l~r的区间哈希值
int main()
{
	int i,j,res=INT_MIN;
	scanf("%s%s",stra+1,strb+1);
	lena=strlen(stra+1);
	lenb=strlen(strb+1);
	lmax=max(lena,lenb);//求最长字符串的长度
	p[0]=1;
	
	for(i=1;i<=lena;i++) hl[i]=hl[i-1]*base+(stra[i]-96);
	for(i=1;i<=lenb;i++) hr[i]=hr[i-1]*base+(strb[i]-96);
	for(i=1;i<=lmax;i++) p[i]=p[i-1]*base;
	//求前缀哈希值
    
	for(i=1;i<=lmax;i++)
	{
		int al,bl;
		if(lena<i||lenb<i) break;//判断边界
		al=get(hl,1,i)!=get(hr,lenb-i+1,lenb)?INT_MIN:i;
        //判断第一个字符串的前缀的区间哈希值和第二个字符串的后缀的区间哈希值是否相等
		bl=get(hl,lena-i+1,lena)!=get(hr,1,i)?INT_MIN:i;
		//判断第一个字符串的后缀的区间哈希值和第二个字符串的前缀的区间哈希值是否相等
		res=max(res,max(al,bl));//求最大值
	}
	printf("%d\n",res);
	return 0;//华丽的结尾~~~
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值