1、KMP算法
设有两串字符,第一串为主串,第二串为副串,求副串在主串的匹配index头。
主要是求next数组,感性认识是副串的前后缀匹配程度:
- "A"的前缀和后缀都为空集,共有元素的长度为0;
- "AB"的前缀为[A],后缀为[B],共有元素的长度为0;
- "ABC"的前缀为[A, AB],后缀为[BC, C],共有元素的长度0;
- "ABCD"的前缀为[A, AB, ABC],后缀为[BCD, CD, D],共有元素的长度为0;
- "ABCDA"的前缀为[A, AB, ABC, ABCD],后缀为[BCDA, CDA, DA, A],共有元素为"A",长度为1;
- "ABCDAB"的前缀为[A, AB, ABC, ABCD, ABCDA],后缀为[BCDAB, CDAB, DAB, AB, B],共有元素为"AB",长度为2;
- "ABCDABD"的前缀为[A, AB, ABC, ABCD, ABCDA, ABCDAB],后缀为[BCDABD, CDABD, DABD, ABD, BD, D],共有元素的长度为0。
class Solution {
public:
int strStr(string haystack, string needle) {
int m = haystack.length(), n = needle.length();
if (!n) {
return 0;
}
vector<int> lps = kmpProcess(needle);
for (int i = 0, j = 0; i < m; ) {
if (haystack[i] == needle[j]) {
i++;
j++;
}
if (j == n) {
return i - j;
}
if ((i < m) && (haystack[i] != needle[j])) {
if (j) {
j = lps[j - 1];
}
else {
i++;
}
}
}
return -1;
}
private:
vector<int> kmpProcess(string& needle) {
int n = needle.length();
vector<int> lps(n, 0);
for (int i = 1, len = 0; i < n; ) {
if (needle[i] == needle[len]) {
lps[i++] = ++len;
} else if (len) {
len = lps[len - 1];
} else {
lps[i++] = 0;
}
}
return lps;
}
};
class Solution { public: vector<int> GetNext(string P) { vector<int> next(P.size(), 0); int p_len = P.size(); int i = 0; // P 的下标 int j = -1; next[0] = -1; while (i < p_len - 1) { if (j == -1 || P[i] == P[j]) { i++; j++; next[i] = j; } else j = next[j]; } vector<int> v2(next.size(), 0); copy(next.begin(), next.end(), v2.begin()); return v2; } //在 S 中找到 P 第一次出现的位置 / int strStr(string S, string P) { int i = 0; // S 的下标 int j = 0; // P 的下标 int s_len = S.size(); int p_len = P.size(); if (!p_len) return 0; vector<int> next = GetNext(P); while (i < s_len && j < p_len) { if (j == -1 || S[i] == P[j]) // P 的第一个字符不匹配或 S[i] == P[j] { i++; j++; } else j = next[j]; // 当前字符匹配失败,进行跳转 } if (j == p_len) // 匹配成功 return i - j; return -1; } };
//优化版 /* P 为模式串,下标从 0 开始 */ void GetNextval(string P, int nextval[]) { int p_len = P.size(); int i = 0; // P 的下标 int j = -1; nextval[0] = -1; while (i < p_len - 1) { if (j == -1 || P[i] == P[j]) { i++; j++; if (P[i] != P[j]) nextval[i] = j; else nextval[i] = nextval[j]; // 既然相同就继续往前找真前缀 } else j = nextval[j]; } }