• [POJ 2774] Long Long Message 【后缀数组】


    题目链接:POJ - 2774

    题目分析

    题目要求求出两个字符串的最长公共子串,使用后缀数组求解会十分容易。

    将两个字符串用特殊字符隔开再连接到一起,求出后缀数组。

    可以看出,最长公共子串就是两个字符串分别的一个后缀的 LCP ,并且这两个后缀在 SA 中一定是相邻的。

    那么他们的 LCP 就是 Height[i] ,当然,Height[i] 的最大值不一定就是 LCS ,因为可能 SA[i] 和 SA[i-1] 是在同一个字符串中。

    那么判断一下,如果 SA[i] 与 SA[i - 1] 分别在两个字符串中,就用 Height[i] 更新 Ans 。

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    
    using namespace std;
    
    const int MaxL = 200000 + 15;
    
    int n, l1, l2, Ans;
    int A[MaxL], Rank[MaxL], Height[MaxL], SA[MaxL];
    int VA[MaxL], VB[MaxL], VC[MaxL], Sum[MaxL];
    
    char S1[MaxL], S2[MaxL];
    
    inline bool Cmp(int *a, int x, int y, int l) {
    	return (a[x] == a[y]) && (a[x + l] == a[y + l]);
    }
    
    void DA(int *A, int n, int m) {
    	int *x, *y, *t;
    	x = VA; y = VB;
    	for (int i = 1; i <= m; ++i) Sum[i] = 0;
    	for (int i = 1; i <= n; ++i) ++Sum[x[i] = A[i]];
    	for (int i = 2; i <= m; ++i) Sum[i] += Sum[i - 1];
    	for (int i = n; i >= 1; --i) SA[Sum[x[i]]--] = i;
    	int p, q;
    	p = 0;
    	for (int j = 1; p < n; j <<= 1, m = p) {
    		q = 0;
    		for (int i = n - j + 1; i <= n; ++i) y[++q] = i;
    		for (int i = 1; i <= n; ++i) {
    			if (SA[i] <= j) continue;
    			y[++q] = SA[i] - j;
    		}
    		for (int i = 1; i <= n; ++i) VC[i] = x[y[i]];
    		for (int i = 1; i <= m; ++i) Sum[i] = 0;
    		for (int i = 1; i <= n; ++i) ++Sum[VC[i]];
    		for (int i = 2; i <= m; ++i) Sum[i] += Sum[i - 1];
    		for (int i = n; i >= 1; --i) SA[Sum[VC[i]]--] = y[i];
    		t = x; x = y; y = t;
    		x[SA[1]] = 1; p = 1;
    		for (int i = 2; i <= n; ++i) 
    			x[SA[i]] = Cmp(y, SA[i], SA[i - 1], j) ? p : ++p;
    	}
    	for (int i = 1; i <= n; ++i) Rank[SA[i]] = i;
    	
    	//GetHeight
    	int h, o;
    	h = 0;
    	for (int i = 1; i <= n; ++i) {
    		if (Rank[i] == 1) continue;
    		o = SA[Rank[i] - 1];
    		while (A[i + h] == A[o + h]) ++h;
    		Height[Rank[i]] = h;
    		if (h > 0) --h;
    	} 
    }
    
    int main() 
    {
    	scanf("%s%s", S1 + 1, S2 + 1);
    	l1 = strlen(S1 + 1);
    	l2 = strlen(S2 + 1);
    	for (int i = 1; i <= l1; ++i) 
    		A[i] = S1[i] - 'a' + 1;
    	A[l1 + 1] = 27;
    	for (int i = 1; i <= l2; ++i) 
    		A[l1 + 1 + i] = S2[i] - 'a' + 1;
    	A[l1 + 1 + l2 + 1] = 28;
    	n = l1 + 1 + l2 + 1;	
    	DA(A, n, 28);	
    	Ans = 0;
    	for (int i = 2; i <= n - 1; ++i) {
    		if (Height[i] > Ans) {
    			if (SA[i] <= l1 && SA[i - 1] > l1 + 1) Ans = Height[i];
    			if (SA[i] > l1 + 1 && SA[i - 1] <= l1) Ans = Height[i];
    		}
    	}
    	printf("%d
    ", Ans);
    	return 0;
    }
    

      

  • 相关阅读:
    jQuery的面试题
    DOM面试题
    JavaScript高级
    Bootstrap面试题
    ajax面试题
    CSS3面试题
    MySQL的列约束
    MySQL数据库介绍
    java数据类型之间的转换
    java中变量和标识符名命名规范
  • 原文地址:https://www.cnblogs.com/JoeFan/p/4215158.html
Copyright © 2020-2023  润新知