写在前:由于哈希没有好好听讲,也没有下来看。这是排位我开的第一道题,直接string暴力T了。昨天其实就看了哈希,太浮躁,于是本来很简单的哈希愣是没看懂。(于是放弃去看爱5了23333333)今天补上。
字符串匹配_哈希
我们将'a' - 'z'字符看成1-26,一个字符串就相当于一个某合适进制的“大数”,那么它的哈希值就是对应位按权相加. 初始化: Hash[0] = 0; Hash[i] = Hash[i - 1] * base + s[i] - 'a' + 1;//所以Hash实际上是一个前缀
为了优化,于是区间的哈希值就有公式:
其中的base就是我们的合适进制,一般是取大质数。对于我们可以预处理出来存在数组p[ ]中,对应,那我们遍历的时候就很方便了。
为了更好地理解这个公式,举个栗子:
比如我们有十进制数211
Hash[0] = 0
Hash[1] = 2
Hash[2] = 2 * 10 + 1 = 21
Hash[3] = (2 * 10 + 1) * 10 + 1 = 211
那么Hash[2, 3] = ?
Hash[2, 3] = Hash[3] - Hash[1] * 100 = 211 - 2 * 100 = 11
Conclusion: 区间求哈希值和上面的过程类似
我们将Hash[ ]用unsighed long long,那么如果万一溢出,会自动取余。这就有可能会造成哈希冲突。但是概率极低。(至于如何解决哈希冲突,我个小白自然是不会了。我师父说叫我百度……等以后做题遇见再说吧。23333333)
SCU - 4438: Censor
- 题意:给一个敏感字符串tar,再给一个目标字符串s。要求是目标字符串中不能出现敏感字符串,一旦出现就删掉咯qwq. (删掉中间的可能前后连起来又出现了敏感字符串),所以最终我们能得到什么合法的字符串呢?字符串可以为空。
- 思路:首先我们就先将敏感字符串的哈希值算出来,然后我们开始遍历目标字符串,将其推入栈中。如果长度大于了敏感字符串的长度len_tar,就以当前位置为结尾字符,往前算len_tar长度的字符串的哈希值,如果和目标字符串的哈希值相等,那么就删掉该字符子串。(对应的操作就是栈顶指针的移动)
- 具体看代码【还有一个操作:字符串输出时,在最后一个有效字符串后面加一个'\0',就直接输出%s即可】
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define INF 0x3f3f3f3f
#define lowbit(x) x & (-x)
#define MID (l + r ) >> 1
#define lsn rt << 1
#define rsn rt << 1 | 1
#define Lson lsn, l, mid
#define Rson rsn, mid + 1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define eps 1e-6
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxN = 5e6 + 5;
const ull base = 131;
ull Hash[maxN], p[maxN];
char s[maxN], tar[maxN], ans[maxN];
void pre()
{
p[0] = 1;
for(int i = 1; i < maxN; i ++ )
p[i] = p[i - 1] * base;
}
int main()
{
pre();
while(~scanf("%s%s", tar, s))
{
int len_tar = strlen(tar);
int len_s = strlen(s);
if(len_s < len_tar)
{
printf("%s\n", s);
continue;
}
ull tar_hash = 0;
for(int i = 0; i < len_tar; i ++ )
tar_hash = tar_hash * base + tar[i] - 'a' + 1;
Hash[0] = 0;
int top = 0;
for(int i = 0; i < len_s; i ++ )
{
ans[top ++ ] = s[i];
Hash[top] = Hash[top - 1] * base + s[i] - 'a' + 1;
if(top >= len_tar && Hash[top] - Hash[top - len_tar] * p[len_tar] == tar_hash)
top -= len_tar;
}
ans[top] = '\0';
printf("%s\n", ans);
}
return 0;
}
贴三个各有优点的Hash讲解
https://www.cnblogs.com/zyf0163/p/4806951.html