HDU 1403-Longest Common Substring (后缀数组)

Description

Given two strings, you have to tell the length of the Longest Common Substring of them.

For example: 
str1 = banana 
str2 = cianaic

So the Longest Common Substring is "ana", and the length is 3.

Input

The input contains several test cases. Each test case contains two strings, each string will have at most 100000 characters. All the characters are in lower-case.

Process to the end of file.

Output

For each test case, you have to tell the length of the Longest Common Substring of them.

Sample Input

banana
cianaic

Sample Output

3

题目大意:给两个字符串,求最长的公共子串的长度。题目分析:扫一遍height数组即可。

代码如下:
# include<iostream>
# include<cstdio>
# include<queue>
# include<cmath>
# include<string>
# include<cstring>
# include<algorithm>
using namespace std;

const int N=100000;

int SA[N*2+5];
int cnt[N*2+5];
int rk[N*2+5];
int tSA[N*2+5];
int height[N*2+5];
int n;
string str;

bool same(int i,int j,int k)
{
	if(tSA[i]!=tSA[j]) return false;
	if(i+k>=n&&j+k<n) return false;
	if(i+k<n&&j+k>=n) return false;
	return tSA[i+k]==tSA[j+k];
}

void buildSA(string s)
{
	int m=27;
	n=s.size();
	for(int i=0;i<m;++i) cnt[i]=0;
	for(int i=0;i<n;++i) ++cnt[rk[i]=s[i]-‘a‘];
	for(int i=1;i<m;++i) cnt[i]+=cnt[i-1];
	for(int i=n-1;i>=0;--i) SA[--cnt[rk[i]]]=i;
	for(int k=1;k<=n;k<<=1){
		int p=0;
		for(int i=n-k;i<n;++i) tSA[p++]=i;
		for(int i=0;i<n;++i) if(SA[i]>=k) tSA[p++]=SA[i]-k;

		for(int i=0;i<m;++i) cnt[i]=0;
		for(int i=0;i<n;++i) ++cnt[rk[tSA[i]]];
		for(int i=1;i<m;++i) cnt[i]+=cnt[i-1];
		for(int i=n-1;i>=0;--i) SA[--cnt[rk[tSA[i]]]]=tSA[i];

		swap(rk,tSA);
		p=1;
		rk[SA[0]]=0;
		for(int i=1;i<n;++i)
			rk[SA[i]]=same(SA[i],SA[i-1],k)?p-1:p++;
		if(p>=n) break;
		m=p;
	}
}

void getHeight()
{
	for(int i=0;i<n;++i) rk[SA[i]]=i;
	int k=0;
	for(int i=0;i<n;++i){
		if(rk[i]==0){
			height[rk[i]]=k=0;
		}else{
			if(k) --k;
			int j=SA[rk[i]-1];
			while(i+k<n&&j+k<n&&str[i+k]==str[j+k]) ++k;
			height[rk[i]]=k;
		}
	}
}

string str1,str2;

bool diff(int i,int j,int m)
{
	if(SA[i]==m||SA[j]==m) return false;
	return (SA[i]-m)/abs(SA[i]-m)*(SA[j]-m)/abs(SA[j]-m)<0;
}

int f(int m)
{
	int ans=0;
	for(int i=1;i<n;++i){
		if(diff(i,i-1,m)&&height[i]>ans)
			ans=height[i];
	}
	return ans;
}

int main()
{
	while(cin>>str1>>str2)
	{
		str=str1+(char)(‘z‘+1)+str2;
		buildSA(str);
		getHeight();
		//cout<<"here is good"<<endl;
		printf("%d\n",f(str1.size()));
	}
	return 0;
}

  


时间: 2024-10-13 16:43:37

HDU 1403-Longest Common Substring (后缀数组)的相关文章

HDU 1403 Longest Common Substring(后缀数组,最长公共子串)

hdu题目 poj题目 参考了 罗穗骞的论文<后缀数组——处理字符串的有力工具> 题意:求两个序列的最长公共子串 思路:后缀数组经典题目之一(模版题) //后缀数组sa:将s的n个后缀从小到大排序后将 排序后的后缀的开头位置 顺次放入sa中,则sa[i]储存的是排第i大的后缀的开头位置.简单的记忆就是“排第几的是谁”. //名次数组rank:rank[i]保存的是suffix(i){后缀}在所有后缀中从小到大排列的名次.则 若 sa[i]=j,则 rank[j]=i.简单的记忆就是“你排第几”

HDU - 1403 - Longest Common Substring

先上题目: Longest Common Substring Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 4010    Accepted Submission(s): 1510 Problem Description Given two strings, you have to tell the length of the Long

HDU 1403 Longest Common Substring(后缀数组啊 求最长公共子串 模板题)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1403 Problem Description Given two strings, you have to tell the length of the Longest Common Substring of them. For example: str1 = banana str2 = cianaic So the Longest Common Substring is "ana", a

HDU 1403 Longest Common Substring(最长公共前缀)

http://acm.hdu.edu.cn/showproblem.php?pid=1403 题意:给出两个字符串,求最长公共子串的长度. 思路: 刚开始学后缀数组,确实感觉很难,但是这东西很强大,所以必须要学会它,推荐罗穗骞大牛的论文. 1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<vector> 6 #i

spoj 1811 LCS - Longest Common Substring (后缀自动机)

spoj 1811 LCS - Longest Common Substring 题意: 给出两个串S, T, 求最长公共子串. 限制: |S|, |T| <= 1e5 思路: dp O(n^2) 铁定超时 后缀数组 O(nlog(n)) 在spoj上没试过,感觉也会被卡掉 后缀自动机 O(n) 我们考虑用SAM读入字符串B; 令当前状态为s,同时最大匹配长度为len; 我们读入字符x.如果s有标号为x的边,那么s=trans(s,x),len = len+1; 否则我们找到s的第一个祖先a,它

hdu_1403_Longest Common Substring(后缀数组的应用)

题目链接:hdu_1403_Longest Common Substring 题意: 给你两个字符串,然你找最长的公共子串 题解: 后缀数组的经典应用,要找两个字符串的公共子串,那么就相当于找两个串的后缀的最长公共前缀,我们将两个字符串拼接在一起,中间插一个特殊字符 然后我们考虑height数组,height数组存的是排i和i-1的最长前缀,如果sa[i]和sa[i-1]在特殊字符的两边,那么这个height[i]记录的就是这两个串的最长 子串,然后扫一遍height数组更新一下答案就行了 1

hdu 2459 Maximum repetition substring(后缀数组)

题目链接:hdu 2459 Maximum repetition substring 题意: 让你找一个重复最多的子串,并且输出. 题解: 这个是论文题,看的cxlove的题解,不是很理解为什么这样就能完全找完,当作结论使吧. 1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i<=b;++i) 3 using namespace std; 4 namespace suffixarray{ 5 #define FN(n) f

spoj1811 Longest Common Substring,后缀自动机

spoj1811LCS 问两个字符串最长公共子串. 做法很简单.匹配成功,则tl++,失败,从父指针回退,tl=t[now].len. 从这题可以清楚了解后缀自动机fa指针的性质: 指向一个状态,这个状态的接受串s[x..x+i]是与当前状态的接受串后缀s[j-i..j]匹配是最长的一个. 这里是不是发现了一个和KMP很像的性质? KMP在失配时通过next数组回退,那么这个回退到的位置i是s[0..i]与当前串的后缀s[j-i..j]匹配最长的一个. 所以. 利用后缀自动机可以求解一个串的子串

spoj 1812 LCS2 - Longest Common Substring II (后缀自动机)

spoj 1812 LCS2 - Longest Common Substring II 题意: 给出最多n个字符串A[1], ..., A[n], 求这n个字符串的最长公共子串. 限制: 1 <= n <= 10 |A[i]| <= 1e5 思路: 和spoj 1811 LCS差不多的做法 把其中一个A建后缀自动机 考虑一个状态s, 如果A之外的其他串对它的匹配长度分别是a[1], a[2], ..., a[n - 1], 那么min(a[1], a[2], ..., a[n - 1]

spoj 1812 LCS2 - Longest Common Substring II (后缀自己主动机)

spoj 1812 LCS2 - Longest Common Substring II 题意: 给出最多n个字符串A[1], ..., A[n], 求这n个字符串的最长公共子串. 限制: 1 <= n <= 10 |A[i]| <= 1e5 思路: 和spoj 1811 LCS几乎相同的做法 把当中一个A建后缀自己主动机 考虑一个状态s, 假设A之外的其它串对它的匹配长度各自是a[1], a[2], ..., a[n - 1], 那么min(a[1], a[2], ..., a[n -