最关键的就是求next数组:
其实我们kmp的思想就是利用之前匹配成功的串,减少匹配次数,以降低时间复杂度;
简单来说就是一个最大前缀和一个最大后缀匹配的问题。
当我们在匹配过程中,匹配失败时,我们可以根据next数组,快速定位以上一个匹配成功的字符结尾的最大后缀。
我们时刻要想着我们求的是最大前缀和最大后缀相同,所以,上一次匹配成功后,我们拿上一次匹配成功的后一个字符和当前字符进行比较;
看看是否一致,如果不一致的话,我们则后退一步,如果还是不一致的话,那我们就接着退,直到退无可退;
如果一致后,那我们令我们的匹配的最大前后缀+1;因为我们没错是拿后面的和前面的匹配,所以我们的数组下标一定要从一开始,否则会越界;
【模板】KMP字符串匹配 - 洛谷
#include
using namespace std;
const int N = 1000010;
string s = " ",t = " ";
int border[N];
int main()
{
string a , b;
cin >> a >> b;
s += a;
t += b;
int n = s.size();
int m = t.size();
//求next数组
for(int i =2 ,j = 0 ;i <= m; i++)
{
while(j && t[i] != t[j+1]) j = border[j];
if(t[i] == t[j+1]) j++;
border[i] = j;
}
//进行匹配
for(int i = 1 ,j = 0 ;i<= n ; i++)
{
while(j && s[i] != t[j+1]) j = border[j];
if(s[i] == t[j+1]) j++;
if(j == m - 1)
{
cout<
字符串哈希说白了就是,将一个字符串映射成一个数字,这样我们每次询问的话都是O(1)的复杂度,接下来我们先来看看如何对字符串进行映射;
我们获取到一个字符串后,将该字符串看成是一个P进制的数;
我们知道如何将二进制转化成十进制;同理我们将一个字符串转化成P进制;
这里我选取对应索引的ASCII作为P进制的乘数;这个数可以随便选取,前提是保证唯一性和不为零;
我们将上述字符串转化:
因为这个数算出来的话会很大,所以我们这里 mod 上一个大质数(为什么是质数,这个和数论有关)这样的话,我们就把一个字符串映射成了一个数。
(这里有人会问,会不会出现冲突,答案是很肯定的,一定会出现冲突,除非我不卡你,这是不可能的);
那有什么用呢,我们可以对字符串进行询问,查看子串匹配问题等等问题;
那接下来我们就来看看如何求一个子串的hash值呢;
下面我们要求从L到R的hash值;
我们知道应该应 1-R 的hash值减去 1 - (L - 1) 的hash值;
我们考虑直接减去的答案对吗,显然是错误的;
因为两者的起点不一样;一个从 R 开始,一个从 L - 1 开始;
这里我们举一个简单的例子:
123456789:(L ~R) = (7 ~ 9)
我们要获得789 能直接用123456789 - 12456吗;
不能;我们要用123456789 - 123456000;
我们要把(1 ~ L - 1) hash值乘上一个 ,这样是不是就对了;
【模板】字符串哈希 - 洛谷
#include
#include
#include
#include
#define x first
#define y second
#define _for(i,s,t) for(int i = (s);i <=t ; i++)
using namespace std;
typedef unsigned long long ULL;
typedef long long LL;
typedef pair PII;
const int N = 100010 ,base = 131,P = 9999971;
int n;
int h[N],idx;
int main()
{
cin>>n;
_for(i,1,n)
{
string str;
cin>>str;
int num = 0;
int m = str.size();
for(int j =0 ;j< m ;j++)
{
num = (num * base +str[j]) % P;
}
h[idx] = num,idx++;
}
sort(h , h + idx);
int res = 0;
for(int i =0 ;i<= n ;i++)
{
if(h[i]!=h[i+1]) res++;
}
cout<
我们根据刚才学的一顿操作完后,喜提一发WA;我们人品不太行,被卡了;
既然我们用一个hash映射不行,那我们就用两个 ------- 双哈希;
所谓双哈希就是我们映射两次;
#include
#include
#include
#include
#define x first
#define y second
#define _for(i,s,t) for(int i = (s);i <=t ; i++)
using namespace std;
typedef unsigned long long ULL;
typedef long long LL;
typedef pair PII;
const int N = 100010 ,base1 = 131,P1 = 9999971,base2 = 101 , P2 = 9999973;
int n;
int h1[N],h2[N],idx;
PII hah[N];
int main()
{
cin>>n;
_for(i,1,n)
{
string str;
cin>>str;
int num1 = 0, num2 = 0 ;
int m = str.size();
for(int j =0 ;j< m ;j++)
{
num1 = (num1 * base1 +str[j]) % P1;
num2 = (num2 * base2 + str[j]) % P2;
}
h1[idx] = num1 , h2[idx] = num2 , idx++;
}
for(int i =0 ;i< idx; i++)
{
hah[i] = {h1[i],h2[i]};
}
sort(hah, hah + idx);
int res = 0;
for(int i =0 ;i<= n ;i++)
{
int a1 = hah[i].x ,a2 = hah[i+1].x;
int b1 = hah[i].y ,b2 = hah[i+1].y;
if(a1 != a2 || b1 != b2) res++;
}
cout<
Novice on the way !