字符串模板 KMP AC自动机 Manacher 后缀数组

有一些板,我以前写了,但是没有存下来,这样就不移动。因此要写到博客上。

KMP

int t1 = 0, t2 = nxt[0] = -1;
while(t1 < tn) if(t2 == -1 || t[t1] == t[t2]) { 
	t1++; t2++;
	if(t[t1] == t[t2]) nxt[t1] = nxt[t2];
	else nxt[t1] = t2;
}else t2 = nxt[t2];
int k = 0;
for(int i = 0; i < sn; i++) {
	while(k && s[i] != t[k]) k = nxt[k];
	if(s[i] == t[k]) k++;
	if(k == tn) printf("Find at %d\n", i);
}

AC AUTOMATON

Updated for 3 times on 2018.3.9

struct node {
	int c;
	node* p, *ch[26];
};
inline node* newnode() {
	node* ret = new node;
	ret->c = 0;
	ret->p = NULL;
	for(int i = 0; i < 26; i++) ret->ch[i] = NULL;
	return ret;
}
node* q[maxn];
int head, tail;
char s[1000050];
char t[100];
node* root;

void insert(char* t) {
	node* o = root;
	for(int i = 0; t[i]; i++) {
		int c = t[i] - 'a';
		if(!o->ch[c]) o->ch[c] = newnode();
		o = o->ch[c];
	}
	o->c++;
}
void buildfail() {
	head = tail = 0;
	q[tail++] = root;
	while(head < tail) {
		node* f = q[head++], *p = NULL;
		for(int i = 0; i < 26; i++) if(f->ch[i]) {
			q[tail++] = f->ch[i];
			if(f == root) {
			    f->ch[i]->p = root;
			    continue;
			}
			p = f->p;
			while(p) {
				if(p->ch[i]) {
					f->ch[i]->p = p->ch[i];
					break;
			    }
				p = p->p;
			}
			if(!p) f->ch[i]->p = root;
		}
	}
}

int query() {
	node* o = root;
	for(int i = 0; s[i]; i++) {
		int c = s[i] - 'a';
		while(o != root && !o->ch[c]) o = o->p;
		o = o->ch[c];
		if(!o) o = root;
		node* cur = o;
		while(cur != root) {
			if(cur->c >= 0) {
			    // what do you want to do
			    //cur->c = -1;
			}//else break;
			cur = cur->p;
		}
	}
}

Manacher

Updated on 2018.3.9

    int n = strlen(s);
	for(int i = 0; i < n; i++) {
		t[i*2] = '$';
		t[i*2+1] = s[i];
	}
	t[n*2] = '$';
	rgt = -1;
	int ans = 0;
	n = n*2 + 1;
	for(int i = 0; i < n; i++) {
		if(rgt >= i) pal[i] = min(pal[2*ct-i], rgt-i); 
		while(i-pal[i]-1 >= 0 && i+pal[i]+1 < n && t[i-pal[i]-1] == t[i+pal[i]+1]) {
		    pal[i]++;
		}
		if(i+pal[i] > rgt) {
			rgt = i + pal[i];
			ct = i;
		}
		ans = max(ans, pal[i]);
	}

SA

char s[maxn];
int sa[maxn], t[maxn], t2[maxn], b[maxn], n;

void buildsa() {
	int i, *x = t, *y = t2;
	for(int i = 0; i < m; i++) b[i] = 0;
	for(int i = 0; i < n; i++) b[x[i]=s[i]]++;
	for(int i = 1; i < m; i++) b[i] = b[i-1];
	for(int i = n-1; i >= 0; i--) sa[--b[x[i]]] = i;
	for(int k = 1; k <= n; k <<= 1) {
		int p = 0;
		for(int i = n-k; i < n; i++) y[p++] = i;
		for(int i = 0; i < n; i++) if(sa[i] >= k) y[p++] = sa[i] - k;
		for(int i = 0; i < m; i++) b[i] = 0;
		for(int i = 0; i < n; i++) b[x[y[i]]]++;
		for(int i = 0; i < m; i++) b[i] += b[i-1];
		for(int i = n-1; i >= 0; i--) sa[--b[x[y[i]]]] = y[i];
		swap(x, y);
		p = 1; x[sa[0]] = 0;
		for(int i = 1; i < n; i++) x[sa[i]] = y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]] ? p-1 : p++;
		if(p >= n) break;
		m = p;
	}
}

void geth() {
	int k = 0;
	for(int i = 0; i < n; i++) rk[sa[i]] = i;
	for(int i = 0; i < n; i++) {
		if(k) k--;
		int j = sa[rk[i]-1];
		while(s[i+k] == s[j+k]) k++;
		h[rk[i]] = k;
	}
}

使用SA可以把LCP问题转化为RMQ问题。
对于多模式匹配,使用 H e i g h t Height Height数组时间复杂度是 O ( m + log ⁡ n ) O(m+\log n) O(m+logn)
更多参见:

哈希

哈希数组可以用线性时间预处理,然后常熟时间得到任意一个字串的哈希值。
基于哈希值的字符串算法真的很不错。——lrj

明天:回文自动机

后缀自动机

Updated on 2018.3.9

//forced by dxymaster
void insert(int x) {
	node* o = newnode(), *p = last;
	last = o;
	o->len = p->len + 1;
	for(; p && !p->ch[x]; p = p->f) p->ch[x] = o;
	if(!p) {
		o->f = root;
		return;
	}
	node* q = p->ch[x];
	if(q->len + 1 == p->len) o->f = q;
	else{
		node* q2 = newnode();
		q2->len = p->len + 1;
		for(char i = 0; i < 26; i++) q2->ch[i] = q->ch[i];
		o->f = q->f = q2; q2->f = p;
		for(; p && p->ch[x] == q; p = p->f) p->ch[x] = q2;
	}
}

Upd on 20180723
上面的是错的

struct node {
	node* ch[26], *f;
	int len, siz;
};
node* _nd = (node*)malloc(1024*1024*450); int noden;
node* root, *last;
inline node* newnode(node* fa) {
	node* ret = _nd+(noden++);
	if(fa) ret->len = fa->len + 1; else ret->len = 0; ret->siz = 0;
	return ret;
}

inline void extend(int x) {
	node* o = newnode(last), *p = last; o->siz = 1;
	last = o;
	for(; p && !p->ch[x]; p = p->f) p->ch[x] = o;
	if(!p) {o->f = root; return;}
	node* q = p->ch[x];
	if(q->len == p->len + 1) o->f = q;
	else{
		node* nq = newnode(p);
		memcpy(nq->ch, q->ch, sizeof(q->ch));
		nq->f = q->f; q->f = o->f = nq; 
		for(; p && p->ch[x] == q; p = p->f) p->ch[x] = nq;
	}
}
int topo_b[maxn], topo[maxn];
inline void get_topo() {
	for(int i = 0; i < noden; i++) topo_b[(_nd+i)->len]++;
	for(int i = 1; i < noden; i++) topo_b[i] += topo_b[i-1];
	for(int i = 0; i < noden; i++) topo[--topo_b[(_nd+i)->len]] = i;
}

最小表示法 upd on 2018.12.28

先将字符串复制一遍。

inline int minr() {
	int i = 0, j = 1;
	while(i < n && j < n) { // n是原串长度
		int k = 0;
		while(s[i+k] == s[j+k] && k < n) k++;
		if(k == n) return min(i, j);
		if(s[i+k] > s[j+k]) i = max(i+k-1, j+1);
		else j = max(j+k-1, i+1);
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值