後綴自動機求兩個串的最長公共子串

假設有兩個串分別爲S, T

求他們的最長公共子串

我們先對S建立後綴自動機, 然後從S的起點u開始, 再記一個長度L, 添加T[1 ~ LenT]

若存在子節點意味着添加當前字符後, 我們可以得到下一個狀態,此時令狀態u = next[u][c], L++.

若不存在, 即不斷跳lnk[u],直到有狀態v滿足next[v][c] != 0,  令u = next[v][c], L = len[v] + 1.

因爲lnk[u]代表着當前u的後綴, 這裏的匹配就與AC自動機的fail指針極其相似。

若一直到起點仍沒有則說明S中不含有c這個字符, 我們初始化u = 1, L = 0即可。

每次操作取個max即可得到答案。

這題後綴數組也能寫, 將兩個串用特殊字符拼接,然後二分長度,

檢測在一段連續的height內, 兩個串是否都出現了 。

不過sam比sa快好多了。。

後綴自動機: 

後綴數組: 

SAM:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <queue>
#include <time.h>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#ifdef LOCAL
#define debug(x) cout << "[" __FUNCTION__ ": " #x " = " << (x) << "]\n"
#define TIME cout << "RuningTime: " << clock() << "ms\n", 0
#else
#define TIME 0
#endif
const int N = 2e5 + 10;
const int mod = 1e9 + 7;
char a[N];
char b[N];
int ans;
struct Suffix_Automata
{
	int len[N << 1];
	int lnk[N << 1];
	int cnt[N << 1];
	int sub[N << 1];
	int nxt[N << 1][26];
	int idx;
	int last;
	void init()
	{
		last = idx = 1;
		lnk[1] = len[1] = 0;
	}
	void clear()
	{
		memset(len, 0, sizeof len);
		memset(lnk, 0, sizeof lnk);
		memset(cnt, 0, sizeof cnt);
		memset(nxt, 0, sizeof nxt);
	}
	void extend(int c)
	{
		int x = ++idx;
		len[x] = len[last] + 1;
		sub[x] = 1;
		int p;
		for (p = last; p && !nxt[p][c]; p = lnk[p])
			nxt[p][c] = x;
		if (!p)
			lnk[x] = 1, cnt[1]++;
		else
		{
			int q = nxt[p][c];
			if (len[p] + 1 == len[q])
				lnk[x] = q, cnt[q]++;
			else
			{
				int nq = ++idx;
				len[nq] = len[p] + 1;
				lnk[nq] = lnk[q];
				memcpy(nxt[nq], nxt[q], sizeof nxt[q]);
				for (; p && nxt[p][c] == q; p = lnk[p])
					nxt[p][c] = nq;
				lnk[q] = lnk[x] = nq;
				cnt[nq] += 2;
			}
		}
		last = x;
	}
}sam;
void solve()
{
	int len2 = strlen(b);
	int u = 1, L = 0;
	for (int i = 0; i < len2; i++)
	{
		int id = b[i] - 'a';
		while (!sam.nxt[u][id] && u != 1)
			u = sam.lnk[u], L = sam.len[u];
		if (sam.nxt[u][id] != 0)
			u = sam.nxt[u][id], ++L;
		ans = max(ans, L);
	}
	cout << ans << endl;
}
int main()
{
#ifdef LOCAL
	freopen("D:/input.txt", "r", stdin);
#endif
	scanf("%s", a);
	int len = strlen(a);
	sam.init();
	for (int i = 0; i < len; i++)
		sam.extend(a[i] - 'a');
	scanf("%s", b);
	solve();
	return TIME;
}

SA

#include <iostream>
//#include <unordered_map>
#include <time.h>
#include <algorithm>
#include <stdio.h>
#include <string.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;

#ifdef LOCAL
#define debug(x) cout << "[" __FUNCTION__ ": " #x " = " << (x) << "]\n"
#define TIME cout << "RuningTime: " << clock() << "ms\n", 0
#else
#define TIME 0
#endif
#define hash_ 1000000009
#define Continue(x) { x; continue; }
#define Break(x) { x; break; }
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
#define gc p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin), p1 == p2) ? EOF : *p1++;
inline int read(){ static char buf[1000000], *p1 = buf, *p2 = buf; register int x = false; register char ch = gc; register bool sgn = false; while (ch != '-' && (ch < '0' || ch > '9')) ch = gc; if (ch == '-') sgn = true, ch = gc; while (ch >= '0'&& ch <= '9') x = (x << 1) + (x << 3) + (ch ^ 48), ch = gc; return sgn ? -x : x; }
ll fpow(ll a, int b, int mod) { ll res = 1; for (; b > 0; b >>= 1) { if (b & 1) res = res * a % mod; a = a * a % mod; } return res; }
int MX;
char str[N];
char str1[N];
char str2[N];
struct Suffix_Array
{
	int n, r; 
	int sa[N]; 
	int cnt[N]; 
	int rak[N]; 
	int tmp[N]; 
	int heig[N]; 
	void radix_sort(int *rk, int *tp)
	{
		memset(cnt, 0, sizeof cnt);   
		for (int i = 1; i <= n; i++)
			cnt[rk[tp[i]]]++;
		for (int i = 1; i <= r; i++) 
			cnt[i] += cnt[i - 1];
		for (int i = n; i >= 1; i--) 
			sa[cnt[rk[tp[i]]]--] = tp[i];
	}
	void suffix()
	{
		int *rk = rak, *tp = tmp;
		for (int i = 1; i <= n; i++)
			rk[i] = str[i], tp[i] = i;
		r = 127; // 0 ~ 127
		radix_sort(rk, tp);
		for (int l = 1, p = 1, i; p < n; l <<= 1, r = p)
		{
			for (p = 0, i = n - l + 1; i <= n; i++) 
				tp[++p] = i;
			for (i = 1; i <= n; i++) 
				if (sa[i] > l)    
					p++, tp[p] = sa[i] - l;
			radix_sort(rk, tp);
			swap(rk, tp);
			rk[sa[1]] = p = 1;
			for (i = 2; i <= n; i++)
			{
				if (tp[sa[i]] != tp[sa[i - 1]] || tp[sa[i] + l] != tp[sa[i - 1] + l])
					p++;
				rk[sa[i]] = p;
			}
		}
	}
	void get_height()
	{
		for (int i = 1; i <= n; i++)
			rak[sa[i]] = i;
		int k = 0;
		for (int i = 1; i <= n; i++)
		{
			if (k)
				k--;     
			int j = sa[rak[i] - 1];
			while (str[i + k] == str[j + k])
				k++;
			heig[rak[i]] = k;
		}
	}
}sa;
int main()
{
#ifdef LOCAL
	freopen("D:/input.txt", "r", stdin);
#endif
	int t;
	cin >> t;
	int cnt = 0;
	scanf("%s", str1 + 1);
	int len = strlen(str1 + 1);
	for (int i = 1; i <= len; i++)
		str[++cnt] = str1[i];
	str[++cnt] = 1;
	scanf("%s", str2 + 1);
	int len2 = strlen(str2 + 1);
	for (int i = 1; i <= len2; i++)
		str[++cnt] = str2[i];
	sa.n = cnt;
	sa.suffix();
	sa.get_height();
	int ans = 0;
	for (int i = 2; i <= sa.n; i++)
	{
		if (sa.heig[i] > ans && (sa.sa[i - 1] <= len && sa.sa[i] > len || sa.sa[i - 1] > len && sa.sa[i] <= len))
			ans = sa.heig[i];
	}
	cout << ans << endl;
	return TIME;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章