宏观
本来使用暴力 O(m*n)的算法,通过KMP方法,基于前缀表构建失败函数next数组,在失败后进行回退,只退模式串指针有效降低了时间复杂度
next数组实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| std::vector<int> build_next(const std::string& pattern) { int n = pattern.length(); std::vector<int> next(n, 0); int j = -1; next[0] = j;
for (int i = 1; i < n; i++) { while (j >= 0 && pattern[i] != pattern[j + 1]) { j = next[j]; }
if (pattern[i] == pattern[j + 1]) { j++; }
next[i] = j; }
return next; }
|
主函数实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| std::vector<int> kmp_search(const std::string& text, const std::string& pattern) { std::vector<int> positions; std::vector<int> next = build_next(pattern); int j = -1;
for (int i = 0; i < text.length(); i++) { while (j >= 0 && text[i] != pattern[j + 1]) { j = next[j]; }
if (text[i] == pattern[j + 1]) { j++; }
if (j == pattern.length() - 1) { positions.push_back(i - j); j = next[j]; } }
return positions; }
|
例题1-28.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| class Solution { public: void getNext(int* next, const string& s){ int j = -1; next[0] = j; for(int i = 1; i < s.size(); i++) { while (j >= 0 && s[i] != s[j + 1]) { j = next[j]; } if (s[i] == s[j + 1]) { j++; } next[i] = j; } } int strStr(string haystack, string needle) { if (needle.size() == 0) { return 0; } int next[needle.size()]; getNext(next, needle); int j = -1; for (int i = 0; i < haystack.size(); i++) { while(j >= 0 && haystack[i] != needle[j + 1]) { j = next[j]; } if (haystack[i] == needle[j + 1]) { j++; } if (j == (needle.size() - 1) ) { return (i - needle.size() + 1); } } return -1; } };
|
总结
对于next数组的理解还不够深入,还不能做到自己完整手撸代码,本周六专门花一天时间突破一下这几天遇到的重难点