Implement strStr().
Returns the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack.
问题:实现 strStr() 函数。即在 haystack 中匹配 needle 字符串。
可以理解为,实际上这道题是在问如何实现 KMP(Knuth–Morris–Pratt) 算法。这是个效率比较高的算法,只需要扫一遍 haystack 就可以得到结果,耗时 O(n) 。在扫之前需要做的是对 needle 字符串预处理,得到 needle 各个前缀字符串[0...i]中 既是真实前缀又是真实后缀的子字符串的最长长度。理解这句话,需要注意的是“既是真实前缀又是真实后缀” 是指在某一 needle前缀而言的。
需要详细理解 KMP 算法,可以参考前一篇文章我所理解的 KMP(Knuth–Morris–Pratt) 算法,或许有帮助。
1 vector<int> LofPS; 2 3 /** 4 * 求 s 中所有前缀字符串[0...i]各自的 既是真实前缀又是真实后缀的子字符串最长长度,存于 LofPS[i]。 5 * 6 * 例如令 len = LofPS[i],则表示 真实前缀s[0...len-1] 和 真实后缀s[ i-len+1...i ] 相等。 7 * 8 */ 9 vector<int> computePrefixSuffix(string s){ 10 11 // LofPS[i] 表示 s[0....i] 部分中,既是真实前缀又是真实后缀的子字符串最长长度。 12 vector<int> LofPS(s.size()); 13 14 if (s.size() == 0) { 15 return LofPS; 16 } 17 18 LofPS[0] = 0; 19 20 int len = 0; 21 int i = 1; 22 23 while (i < s.size()) { 24 25 if (s[i] == s[len]) { 26 len++; 27 LofPS[i] = len; 28 i++; 29 continue; 30 } 31 32 if (len != 0) { 33 // 利用之前计算的结果。这里是一个需要理解的点。 34 // 根据已计算的 LofPS[len-1]部分 真实前缀、真实后缀的相等的最长长度,定位同样匹配 s 前缀但是更短的子字符串。 35 len = LofPS[len - 1]; 36 }else{ 37 LofPS[i] = 0; 38 i++; 39 } 40 } 41 42 return LofPS; 43 } 44 45 46 int strStr(string haystack, string needle) { 47 48 // 计算 needle 中所有前缀字符串[0...idx]各自的真实前缀且是真实后缀的最长长度。 49 vector<int> tmp(needle.size()); 50 LofPS = tmp; 51 52 LofPS = computePrefixSuffix(needle); 53 54 int i = 0 ; 55 int k = 0; 56 57 while (i < haystack.size() && k < needle.size()) { 58 if (haystack[i] == needle[k]) { 59 i++; 60 k++; 61 continue; 62 } 63 64 if (LofPS[k-1] != 0) { 65 k = LofPS[k-1]; 66 continue; 67 } 68 69 if (haystack[i] == needle[0]) { 70 k = 1; 71 i++; 72 }else{ 73 k = 0; 74 i++; 75 } 76 } 77 78 if (k == needle.size()) { 79 return i - k; 80 }else{ 81 return -1; 82 } 83 }