📅  最后修改于: 2023-12-03 14:58:37.533000             🧑  作者: Mango
本题为门 | 门CS 2013 | 第49题。题目难度为普及+/提高,需要具有一定的数据结构和动态规划基础。
给定两个字符串 $S$ 和 $T$,求出 $S$ 中有多少个子串与 $T$ 相同。
输入文件包含两行,第一行为字符串 $S$,第二行为字符串 $T$。
输出文件包含一个整数,即 $S$ 中有多少个子串与 $T$ 相同。
helloello
ello
2
hello
ab
0
本题主要考察的是字符串匹配算法。常用的字符串匹配算法包括暴力枚举算法、KMP算法、Boyer-Moore算法等。这里给出两种解题思路。
对于每个字符 $S[i]$,从 $i$ 开始,逐一比较 $S[i]$ 和 $T[j]$ 是否相等,如果相等则继续比较下一个字符,直到 $T$ 中的所有字符都匹配上了,则说明找到了一个子串与 $T$ 相同。
时间复杂度为 $O(n^2)$,空间复杂度为 $O(1)$。
KMP算法是一种高效的字符串匹配算法,用于在一个长文本串 $S$ 中,查找一个模式串 $T$ 的出现位置。
具体算法流程如下:
根据模式串 $T$,计算出前缀表 $next$ 数组。$next[i]$ 表示模式串 $T[0...i]$ 的最长公共前后缀的长度。
对于字符串 $S$,从左到右依次比较字符。当字符不匹配时,根据 $next$ 数组将模式串向右移动一定距离。具体做法是将模式串向右移动 $i - next[i]$ 个字符。
时间复杂度为 $O(n)$,空间复杂度为 $O(m)$($m$ 为模式串长度)。
#include <iostream>
#include <cstring>
using namespace std;
int main() {
string s, t;
cin >> s >> t;
int cnt = 0;
for (int i = 0; i < s.size(); i++) {
int j = 0;
while (j < t.size() && i+j < s.size() && s[i+j] == t[j])
j++;
if (j == t.size())
cnt++;
}
cout << cnt << endl;
return 0;
}
#include <iostream>
#include <cstring>
using namespace std;
void getNext(string t, int next[]) {
int j = 0, k = -1;
next[0] = -1;
while (j < t.size() - 1) {
if (k == -1 || t[j] == t[k]) {
j++;
k++;
next[j] = k;
} else {
k = next[k];
}
}
}
int kmp(string s, string t) {
int next[t.size()];
getNext(t, next);
int i = 0, j = 0, cnt = 0;
while (i < (int)s.size()) {
if (j == -1 || s[i] == t[j]) {
i++;
j++;
} else {
j = next[j];
}
if (j == (int)t.size()) {
cnt++;
j = next[j];
}
}
return cnt;
}
int main() {
string s, t;
cin >> s >> t;
cout << kmp(s, t) << endl;
return 0;
}