字符串学习笔记

字符串学习笔记

哈希

最基础的字符串算法, 规定一个质数(p), 将字符串转换为一个(p)进制的数

字符串最小循环表示法

咕咕咕

KMP

定义需要被匹配的串叫做

我们知道暴力算法是在每一个位置开始匹配, 匹配不成功时位置++

这样的算法最好时间复杂度是(O(原串长度)), 最坏时间复杂度是(O(原串长度*匹配串长度))

考虑对暴力算法的优化

我们知道对于一个字符串, 若它在当前位置匹配不成功, 并且出现了这样一个情况

1.png

这个红色和蓝色是满足相等的条件下的, 最长的前缀和后缀, 若此时指针在蓝色右边, 我们可以直接将指针移至红色端点右边, 继续匹配

对于一个字符串(S), 它的长度为(n)

我们设(nxt[i])为满足对于(S)的一个字串(S[1 - i]), 有(S[1 - nxt[i]]) = (S[(i - nxt[i] + 1) - i])这一条件的最大的下标

那么我们对于字符串匹配就有了这样的算法

	for(int i = 1; i <= n; i++)
	{
		while(pos && s2[pos + 1] != s1[i])
			pos = nxt[pos];//无法匹配时跳到nxt处继续匹配
		if(s2[pos + 1] == s1[i]) pos++;//若相等指针后移
		if(pos == m)//整个字符串完成匹配
		{
			printf("%d
", i - pos + 1);
			pos = nxt[pos]; //重新开始匹配
		}
	}

现在所求就变成了怎么求nxt数组

我们考虑这样一个过程

(S[1 - (i - 1)])(S[1 - i])匹配, 当原串的指针超出原串范围时, 此时匹配串的指针即为(nxt[i])

因为此时(S[1 - nxt[i]])(S[(i - nxt[i] + 1) - i])相同

若此时(S[1 - nxt[i]])不为最长子串, 那么在上一次跳(nxt)时是不会跳到当前位置的, 而会跳到最长子串所在的位置

感性理解一波

对于每次新加上一个字母, 我们没有必要去重新匹配, 可以直接在原来的基础上继续匹配, 具体原因感性理解一下吧, 在两个不匹配的字符串的后面加上不同的字母对匹配是没有影响的

于是有

	for(int i = 2; i <= m; i++)
	{
		while(pos && s2[pos + 1] != s2[i])
			pos = nxt[pos];
		if(s2[pos + 1] == s2[i]) pos++;
		nxt[i] = pos; 
	}

我在学习的时候发现了一个问题, 是这样的, 有没有可能在从(i)跳到(nxt[i])的过程中, 跳过了一些可能对答案造成贡献的点, 也就是:

2.png

红点是(i), 蓝点是(nxt[i]), 紫串是(S[1 - nxt[i]]), 绿串是同时存在于前缀和后缀的一个比紫串更加长的子串

显然矛盾, 如果有这种情况, 那么(nxt[i])就是绿色的左边了

康康别人的博客吧, 这个我自己能看懂就行

ExKMP

咕咕咕

后缀数组

咕咕咕

后缀自动机

咕咕咕

回文自动机

咕咕咕

AC自动机

咕咕咕

KMP自动机

咕咕咕

Manacher

咕咕咕

原文地址:https://www.cnblogs.com/ztlztl/p/11627623.html