码迷,mamicode.com
首页 > 其他好文 > 详细

字符串基础知识

时间:2015-04-08 21:22:01      阅读:129      评论:0      收藏:0      [点我收藏+]

标签:

一) kmp

用于一个串的自我匹配或者与另一个串的匹配。

       int j = -1;
    next[0] = -1; //!!!!!!!!!
    for(int i = 1; i < lena; i ++){ while(j >= 0 && a[j + 1] != a[i])j = next[j]; if(a[j + 1] == a[i])j ++; next[i] = j; } j = -1; for(int i = 0; i < lenb; i ++){ while(j >= 0 && a[j + 1] != b[i])j = next[j]; if(a[j + 1] == b[i])j ++; if(j == lena - 1){ ans ++; j = next[j]; }

易错点

第一个元素的next值是要特判的, 不然会有问题。

应用

找最小循环节

一个有循环节 k 的串  它从第k + 1 位到第 n 位的next数组是单调的。

当然SA也可以O(n) 找最小循环节, 但代码量差了太多,,

 

二) ac 自动机

一个串与多个串的匹配。

void insert(char *s){
	int len = strlen(s), now = root;
	for(int i = 0; i < len; i ++){
		if(next[now][s[i] - ‘a‘] == -1)next[now][s[i] - ‘a‘] = newnode();
		now = next[now][s[i] - ‘a‘];
	}end[now] ++;
}
void build(){
	queue<int>q;
	fail[root] = root; //!!!!!!!!!!
	for(int i = 0; i < 26; i ++)
		if(next[root][i] == -1)next[root][i] = root;
		else{
			fail[next[root][i]] = root;
			q.push(next[root][i]);
		}
	while( ! q.empty()){
		int now = q.front(); q.pop();
		for(int i = 0; i < 26; i ++)
			if(next[now][i] == -1)next[now][i] = next[fail[now]][i];
			else{
				fail[next[now][i]] = next[fail[now]][i];
				q.push(next[now][i]);
			}
	}
}

 ac自动机把kmp的母串拓展到多个, 即计算一棵Trie树的fail数组

由于fail数组的单调性(p节点的fail一定指向一个深度小于p的点)所以在构造的时候 bfs 一遍就可以了。

一个优化是 如果next[p][c] 为空, 那么把它指向next[f][c] (f是p的所有next[x][c]不为空的祖先x中深度最大的节点)。

因为考虑寻找fail以及匹配的时候如果 next[p][c] 为空, 我们就会把它一直while上去直到一个非空的祖先,但是这一步在很多题中是可以直接在bfs的时候这样预处理出来的。 这样才能保证构建fail指针的复杂度是严格 O(字符串长度) 的。

当然在一些题中这种做法(由于空间限制或者题目需要)是行不通的,这时候只能用不改变next数组的复杂度没有保证的ac自动机, 或者用其它东西来搞啦。

易错点

注意 ac自动机的root 节点的 fail指针也是要特判的!!!

技巧

这个串走到的所有的节点,以及这些节点一路往根fail的节点,都是这个串的子串 (任意一个前缀的任意一个后缀)

1) end数组

end 数组的基本用法是存trie树中的这个点是否是一个字符串的结尾, 但考虑到如果当前节点是当前匹配到的串的后缀, 那么它的后缀还是当前匹配到的串的后缀, 所以在一些题中可以用end数组记录下fail[end], fail[fail[end]] …… root 的信息。 (用 + 或是 |)

2)fail树的构造

在一些题中(经常是要对子串进行修改的时候), 无法只用一个end就记录下fail[end], fail[fail[end]] …… root 的信息。 这时候考虑把所有fail的边反向, 于是就构成了一棵树。然后问题转变为在一棵子树上的一些操作, 这个时候就可以用树状数组线段树之类的来水了。

例, [Noi2011]阿狸的打字机, hdu4117 GRE words, cf 163E

应用

基本的就是 一个(些)(……的)字符串在一个(些)(……的)字符串中出现了多少次

然后似乎就没有什么其它的应用了?

 

三)后缀数组

 

字符串基础知识

标签:

原文地址:http://www.cnblogs.com/lixintong911/p/4403575.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!