前两天主要在写洛谷上的题目,对于KMP和hash也大致理解了一些东西,比较简单的题目还是能够套用模板修修改改写出来,但是难一点的题目就会完全没有思路,还是需要多看多想
P3375 【模板】KMP - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
题目描述
给出两个字符串 s1 和 s2,若 s1 的区间 [l,r] 子串与 s2 完全相同,则称 s2 在 s1 中出现了,其出现位置为 l。
现在请你求出 s2 在 s1 中所有出现的位置。
定义一个字符串 s 的 border 为 s 的一个非 s 本身的子串 t,满足 t 既是 s 的前缀,又是 s 的后缀。
对于 s2,你还需要求出对于其每个前缀 ′s′ 的最长 border ′t′ 的长度。
输入格式
第一行为一个字符串,即为 s1。
第二行为一个字符串,即为 s2。
输出格式
首先输出若干行,每行一个整数,按从小到大的顺序输出 s2 在 s1 中出现的位置。
最后一行输出 ∣s2∣ 个整数,第 i 个整数表示 s2 的长度为 i 的前缀的最长 border 长度。
输入输出样例
输入
ABABABC ABA
输出
1 3 0 0 1
思路:这道题是一道纯KMP题,套用KMP的模板就可以写出来,但是前缀数组要进行两次操作,第一次是样例字符串(题目样例中较短的那个字符串)的前缀数组,第二次就是把样例和模板字符串进行比较从而得到最长的相同前后缀长度
代码:
#include<iostream>
#include<cstring>
using namespace std;
int kmp[1000005];
char a[1000005], b[1000005];
int main() {
cin >> a + 1;
cin >> b + 1;
int lena = strlen(a + 1);
int lenb = strlen(b + 1);
int j = 0;
for (int i = 2; i <= lenb; i++) {
while (j > 0 && b[i] != b[j + 1]) {
j = kmp[j];
}
if (b[i] == b[j + 1]) {
j++;
kmp[i] = j;
}
}
j = 0;
for (int i = 1; i <= lena; i++) {
while (j > 0 && a[i] != b[j + 1]) {
j = kmp[j];
}
if (a[i] == b[j + 1]) {
j++;
}
if (j == lenb) {
cout << i - j + 1 << endl;
j = kmp[j];
}
}
for (int i = 1; i <= lenb; i++)
cout << kmp[i] << " ";
}
P3370 【模板】字符串哈希 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
题目描述
如题,给定 N 个字符串(第 i 个字符串长度为 Mi,字符串内包含数字、大小写字母,大小写敏感),请求出 N 个字符串中共有多少个不同的字符串。
友情提醒:如果真的想好好练习哈希的话,请自觉。
输入格式
第一行包含一个整数 N,为字符串的个数。
接下来 N 行每行包含一个字符串,为所提供的字符串。
输出格式
输出包含一行,包含一个整数,为不同的字符串个数。
输入输出样例
输入
5 abc aaaa abc abcc 12345
输出
4
思路:这道模板题用了两种方法来写,一种是纯hash,另一种是使用STL里的map来写
代码:
//hash
#include<iostream>
#include<algorithm>
using namespace std;
int a[10005];
int base = 131;
int hashe(string ss) {
int ans = 0;
int len = ss.size();
for (int i = 1; i <= len; i++) {
ans = (ans * base + (int)ss[i]) % 20000000;
}
return ans;
}
int main() {
int n;
string s;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> s;
a[i] = hashe(s);
}
sort(a + 1, a + 1 + n);
int ans = 1;
for (int i = 1; i < n; i++) {
if (a[i] != a[i + 1])ans++;
}
cout << ans;
return 0;
}
//map
#include<iostream>
#include<map>
using namespace std;
map<string, int>mp;
int main() {
int n;
cin >> n;
string s;
for (int i = 1; i <= n; i++) {
cin >> s;
mp[s]++;
}
cout << mp.size();//mp.size() 是一个成员函数,用于返回 mp 映射中存储的键值对的数量。换句话说,它返回了 mp 中有多少个不同的键。
return 0;
}