求两个字符串的最长公共连续子序列(SAM实现)

//时间复杂度O(N)
#include <stdio.h>
#include <cstring>
const int R = 26;
const int N = 250005; //字符串的长度
struct node{
	node *next[R], *par; 
	int v; //该节点表示的子串的最大长度,最小长度即为par的最大长度+1,因此可以不用存下来
}nodes[N*2+100], *root;
int cnt;  //树中节点个数
node* newNode(int v, node* par){
	nodes[cnt].v = v; 
	nodes[cnt].par = par; 
	memset(nodes[cnt].next, 0, sizeof(node*)*R); 
	return &nodes[cnt++]; 
}
inline int id(char ch){
	return ch-'a'; 
}
//构造后缀自动机
void SAM(char* str, node*& root){
	cnt = 0; 
	node *last, *now, *np; 
	last = root = newNode(0, NULL);
	int i, k; 
	for(i = 0; str[i]; i++){
		now = last; 
		k = id(str[i]); 
		np = newNode(i+1, NULL); 
		while(now && ! now->next[k]){
			now->next[k] = np; 
			now = now->par; 
		}
		if(!now){
			np->par = root; 
		}else if(now->next[k]->v == now->v+1){
			np->par = now->next[k]; 
		}else{
			node* t = now->next[k]; 
			node* nt = newNode(now->v+1, t->par); 
			t->par = np->par = nt; 
			memcpy(nt->next, t->next, sizeof(node*)*R); 
			while(now && now->next[k] == t){
				now->next[k] = nt; 
				now = now->par;
			}
		}
		last = np; 
	}
}
inline void upMax(int& a, int tmp){
	if(a < tmp) a = tmp;
}
//求字符串sa和sb的最长公共连续子序列
int maxCommonLen(char* sa, char* sb){
	cnt = 0; 
	SAM(sa, root); 
	//test(); 
	node *now;
	now=root;
	int i, k, ans, len;
	ans = len = 0; 
	for(i = 0; sb[i]; i++){
		k = id(sb[i]); 
		if(now->next[k]){
			len++; 
			now = now->next[k];
		}else{
			while(now && ! now->next[k]){
				now = now->par; 
			}
			if(now){
				len = now->v + 1; 
				now = now->next[k]; 
			}else{
				now = root; 
				len = 0; 
			}
		}
		upMax(ans, len); 
	}
	return ans; 
}
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值