今天听了洛谷的字符串课之后,对于自己好好学学字符串算法也有了更大的动力。
但由于比较弱,所以先从最最简单的一个开始。
也就是哈希算法。
哈希算法是什么?
它通过给每个字符串赋予一个「随机」生成的整数的方法,使得可以用更加快的效率实现字符串判重或者匹配字符串等等操作。
比如说如果有两个字符串S和S’(长度分别为L和L’),而我们要比较它们是否具有包含关系。
枚举这个公共字串的开头的话,复杂度是O(LL’)的,对于许多字符串题来说都太慢了过不去。
哈希算法相当于是把字符串表示成一个k进制数:
H(C)=(c1km−1+c2km−2+c3km−3+...+cmb0)modh
H
(
C
)
=
(
c
1
k
m
−
1
+
c
2
k
m
−
2
+
c
3
k
m
−
3
+
.
.
.
+
c
m
b
0
)
m
o
d
h
其中k,h是大于字符串长度且互质的质数。
并且有一个滚动哈希的优化可以直接将字符串匹配的复杂度降到O(L+L’)
H(S[a+1...a+m])=(H(S[a...a+m−1]∗k−sakm+sa+m))
H
(
S
[
a
+
1...
a
+
m
]
)
=
(
H
(
S
[
a
.
.
.
a
+
m
−
1
]
∗
k
−
s
a
k
m
+
s
a
+
m
)
)
有什么缺点吗?
有的,因为不同字符串的哈希值是有一定可能相等的,所以应该用一些奇怪的方法来判断哈希值相同的字符串到底是不是同一个字符串。(不过我暂时不会qwq)
但是,如果两个字符串的哈希值不相同,那么它们一定不是相同的字符串!
代码实现?
暂时只会最简单的。(这是洛谷上面哈希模版可以AC的代码)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef unsigned long long ull;
const ull B = 127;//这是个超可爱的数字!并且还是个质数ww
ull mod=212370440130137957ll;//从dalao题解上面抄的大质数
ull h[1505];
ull hashh(char s[])
{
int len=strlen(s);
ull ans=0;
for(int i=0;i<len;i++)
ans=(ans*B+(ull)s[i])%mod;
return ans;
}
int main()
{
int n;
scanf("%d",&n);
char a[1505];
for(int i=1;i<=n;i++)
{
scanf("%s",a);
h[i]=hashh(a);
}
sort(h+1,h+n+1);
int res=1;
for(int i=2;i<=n;i++)
{
if(h[i]!=h[i-1]) res++;
}
printf("%d\n",res);
return 0;
}