由于博主自己不大会字符串算法,于是照旧打算从头写起
又名暴力匹配算法(Brute Force Algorithm)
没有预处理
失配后向后移动一位
复杂度:$O(n^2)$
Code
1 | void (char *a,char *b) |
哈希($Hash$)是一种鹅妹子嘤的算法
在预处理后可以做到$O(1)$查找一个对象
一句话原理:以空间换时间。 ——蒋介石
具体实现:
栗子:
设计一个程序,以完成以下输入输出:
第一行,输入两个数字$n,m$。
第二行,输入$n$个字符串。
第三行,输入$m$个字符串。对于每一个字符串,询问其是否存在于第二行输入$n$个字符串中,若是则输出”YES”,若不是则输出”NO”。数据说明:输入的字符串的长度范围在$[1,10^5]$。
如果这道题的字符串都改成数字$[1leqslant a leqslant10^5]$,那是个人都会做,只要建一个$bool$数组$vis[10^5]$记录每一个数字是否出现过就做完了。
现在变成了字符串,也是可以做的;
因为有一个东西叫做$map$;
但是这个东西常数大啊怎么办?
没事,可以自己手写;
我们把每一个字符串看成一个$M$进制的$len$位数,其中这里$M$表示大于字符集大小的一个数,可以取130,233,666什么的。
为了避免溢出,我们对这个大数进行一个取模,$mod$可以取一个类似$99991$的质素。
Code
1 | const int M = 131; |
那么问题来了,如果$hash$的值冲突怎么办呢?
1、通过增大哈希池大小来降低哈希值碰撞的问题,即调大$vis$数组大小与$mod$的大小(双模数Hash也可以),不足之处显而易见,空间大小有限定。
2、对于每个字符串的哈希值记录原有字符串,在冲突的情况下用别的方法匹配($NSMA$或$KMP
$)。
Hash如果不做一些特别的处理,很容易被卡,望各位自重。
我们来观察一下$NSMA$算法,发现每一次模式串失配后文本串只会往后跳一位且重置模式串至第一位。
实际上我们并没有必要每一次都把模式串重置


设文本串为$s_1$,模式串为$s_2$,当前匹配到$s_1$的的第$i$个位置,$s_2$的第$j$个位置,$s_1[i] neq s_2[j]$
如果存在一个$k$,使得$s_2[1 cdots k] = s_2[j - k cdots j - 1]$,则$j$不必再重置至第一位,可以直接重置至第$k$位,因为前面的字符都一样。

重点来了:如何求这些$k$是多少呢?
因为在模式串的每一个位置都有可能发生失配,所以我们要对每一个$j$求出它对应的$k$,用$next$数组来存,$next[j] = k$,表示当$s_2[j] != s_1[i]$时,$j$的指针的下一个位置。
当$j = 1$时,显然失配后只能重新开始匹配,所以$next[1] = 0$,木得问题。
当$j > 1$时呢?如图。


我们可以发现:当$p[k] = p[j]$时,有$next[j + 1] = next[j] + 1$
看图感性理解,易证,留给读者当作业(滑稽.jpg)
如果$p[k] ne p[j]$怎么办呢?
如图:

此时,我们应将$k$的值赋为$next[k]$,因为我们已经找不到一个最长的前缀串满足$s_2[1 cdots k] = s_2[j - k cdots j - 1]$,所以我们只能找次小的前缀串满足该条件,显然,这个次小的前缀串就是$next[k]$。
小优化:
按上述方法找到的$next$大致上已经没什么问题了,但是遇到部分情况还是会多出一切不必要的比较。
如下图:

显然,在上述匹配过程中,当前位置产生失配时,$j$会跳到$next[j]$,也就是$2$,但是,这一步是完全没有意义的,因为我们已经知道这一位用$B$去匹配是会失配的,在跳了一下$next$数组后,我们用来匹配的字符却还是$B$,显然还是失配的。
解决:在求$next$时判一个相等就好了。
Code
1 |
|
对于多字符串的匹配问题,我们一般会用$Hash$或者$Trie$储存。
此处不讲$Hash$($hash$大法好啊)
$AC$自动机是什么?在$trie$上搞一个类似$KMP$的那个$next$数组的一个失配指针。我们用$fail$来表示这个东西。
我们先对题中给出若干个模式串建出一颗$trie$树,不过我们对这个数的每一个节点都添加一个信息,就是该节点的$fail$指针。
那我们怎么求这个$fail$指针呢?首先,深度为$2$的节点(即根节点的儿子)的$fail$指针都指向根节点,然后对于每一个节点$v$,它的$fail$指向:沿着它的父亲节点的失配指针,一直向上,直到我们找到拥有当前字母的子节点的节点的那个子节点。
具体实现可以看yyb大佬的代码
Code
1 |
|
原文:https://www.cnblogs.com/lijianming180/p/12370814.html