【循环KMP】重叠字符串匹配
循环字符串匹配
给定两个字符串 a 和 b,寻找重复叠加字符串 a 的最小次数,使得字符串 b 成为叠加后的字符串 a 的子串,如果不存在则返回 -1。
注意:字符串 "abc" 重复叠加 0 次是 "",重复叠加 1 次是 "abc",重复叠加 2 次是 "abcabc"。
二分 + find
也不是不行,但仔细想想就知道这是很傻的做法了。\(O(2n\log\frac{n}{m} )\)。
class Solution {
public:
int repeatedStringMatch(string a, string b) {
// binary search
auto check = [&](int m) {
string aa;
while (m--) aa += a;
if (aa.find(b) != -1) return true;
else return false;
};
int l = 0, r = b.size() / a.size() + 1;
while (l <= r) {
int m = (l + r) >> 1;
if (check(m)) r = m - 1;
else l = m + 1;
}
if (check(l)) return l;
else return -1;
}
};
find
因为其实一次find加贪心就可以得到答案:\(O(2n)\)
class Solution {
public:
int repeatedStringMatch(string a, string b) {
int an = a.size(), bn = b.size();
string aa;
while (aa.size() <= bn + an) aa += a; // important!
int index = aa.find(b);
if (index == -1) return -1;
if (an - index >= bn) return 1;
return (bn + index - an - 1) / an + 2;
}
};
循环KMP
手写KMP并修改,使其可以循环匹配母串。\(O(n+m)\)
class Solution {
public:
int strStr(string& t, string& p) {
int n = t.size(), m = p.size();
if (m == 0) return 0;
// get next
vector<int> next(m);
for (int i = 1, j = 0; i < m; i++) {
while (j > 0 && p[i] != p[j]) j = next[j - 1];
if (p[i] == p[j]) j++;
next[i] = j;
}
// match
for (int i = 0, j = 0; i - j < n; i++) {
// note the `i % n`, since we want a cyclic t.
while (j > 0 && t[i % n] != p[j]) j = next[j - 1];
if (t[i % n] == p[j]) j++;
if (j == m) return i - m + 1;
}
return -1;
}
int repeatedStringMatch(string a, string b) {
int an = a.size(), bn = b.size();
int index = strStr(a, b);
if (index == -1) return -1;
if (an - index >= bn) return 1;
return (bn + index - an - 1) / an + 2;
}
};
循环Rabin-Karp
滚动哈希。\(O(n+m)\)
class Solution {
public:
constexpr int kMod1 = 1e9 + 7;
constexpr int kMod2 = 1337;
int strStr(string haystack, string needle) {
int n = haystack.size(), m = needle.size();
if (m == 0) {
return 0;
}
long long hash_needle = 0;
for (auto c : needle) {
hash_needle = (hash_needle * kMod2 + c) % kMod1;
}
long long hash_haystack = 0, extra = 1;
for (int i = 0; i < m - 1; i++) {
hash_haystack = (hash_haystack * kMod2 + haystack[i % n]) % kMod1;
extra = (extra * kMod2) % kMod1;
}
for (int i = m - 1; (i - m + 1) < n; i++) {
hash_haystack = (hash_haystack * kMod2 + haystack[i % n]) % kMod1;
if (hash_haystack == hash_needle) {
return i - m + 1;
}
hash_haystack = (hash_haystack - extra * haystack[(i - m + 1) % n]) % kMod1;
hash_haystack = (hash_haystack + kMod1) % kMod1;
}
return -1;
}
int repeatedStringMatch(string a, string b) {
int an = a.size(), bn = b.size();
int index = strStr(a, b);
if (index == -1) {
return -1;
}
if (an - index >= bn) {
return 1;
}
return (bn + index - an - 1) / an + 2;
}
};