Implement strStr
Implement strStr().
Returns a pointer to the first occurrence of needle in haystack, or null if needle is not part of haystack.
思路:朴素算法和KMP,此外还有Karbin-ship算法。关于next的数组,只需要知道一点:求patten串i位置(包括自己)最大前缀子串的长度,这个长度其实就是将来i+1的位置失配之后,下一次j重新比较的位置。也可以理解为一个dp的过程
#include <iostream> #include <string.h> #include <assert.h> using namespace std; class Solution { public: int * next(char * p){ assert(p); int len = strlen(p); int * n = new int[len]; n[0] = 0; int k = 0; for(int i = 1; i < len; i++){ k = n[i-1]; while(k > 0 && p[k] != p[i]){ k = n[k-1]; } if (p[k] == p[i]){ n[i] = k + 1; }else{ n[i] = 0; } } return n; } /** 一下两种算法:1) if (j == size2) 统一放在for循环的里面,意味着找到满足匹配的就输出. 如果要求全部输出,那就需要在这里变形 2) &haystack[i - j] 返回的位置而言,朴素算法中,i和j是同步往前移动的,故最后返回的是 haystack[i - j] 但是KMP的算法中,i的循环是在for中,j的循环是在 return的前面,意味着i比j在当前的位置晚 1 步,所以最后输出的为止在haystack[i - j + 1] 3) 二者的for循环的边界都是在 i < size1,而j < size2 不需要判断,因为不可能超过的,j每次都往前最多走一步,而中间循环里面判断是否 j == size2 就决定退出 4) 关于复杂度的分析,朴素的算法最坏情况是 O(M*N)(i回退,每次最多回退j步).而KMP的复杂度是O(M+N),是因为j = n[j-1],能让j很快就退到0,而大部分情况是1步就回退到0的,总体而言,平均回退的步数不会超过2,总体是2*j.最后的复杂度是O(M+N) */ char *strStrNormal(char *haystack, char *needle){ assert(haystack && needle); int size1 = strlen(haystack); int size2 = strlen(needle);
if (size1 < size2){ return NULL; } int i = 0, j = 0; //去掉了 j < size2 的条件 while(i < size1){ if (haystack[i] == needle[j]){ i++; j++; //j往前面移动了j步,意味着i也是往前移动了i步,下次就要回退 j - 1 }else{ i = i - j + 1; //失配之后下一次匹配是 i+1的位置 j = 0; } if (j == size2){ //如果成功,那么j的位置肯定是在 needle.size(),难道不是吗? return &haystack[i - j]; //如果搞不清楚 是应该i -j or i - j +1,直接想想如果两个串一样的情况下,当然是i-j = 0 为位置 } } return NULL; } char *strStrKmp(char *haystack, char *needle) { assert(haystack && needle); int size1 = strlen(haystack); int size2 = strlen(needle); if (size1 < size2){ return NULL; } /**s |<- strlen(haystack) means end().相当于end()往左游走 strlen(needle)个元素,正好在needle起始的为止 XXXXXXXXXXX0 YYYY | last_index char * haystack = "ababc0000"; char * needle = "ababc"; return NULL, 有BUG,是因为j == size2应该在for循环里面,如果ok,就应该输出 */ int j = 0, i = 0; //获取特征数组 int * n = next(needle); for(; i < size1; i++){ //如果不等于,j就回退通过next数组,找到下一个合适比较的为止 直到相等或者j = 0 while(j > 0 && needle[j] != haystack[i]){ j = n[j - 1]; } //如果j退到0的为止. if (needle[j] == haystack[i]){ //相等就i++,j++,如果都不相等,那么i++,j回退到合适的为止 j++; } if (j == size2){ return &haystack[i - j + 1]; } } return NULL; } char *strStr(char *haystack, char *needle){ //return strStrNormal(haystack,needle); return strStrKmp(haystack,needle); } }; using namespace std; int main(int argc, char *argv[]) { char * haystack = "sdsdasdababcdsdedsdsdsdsdsds"; char * needle = "edsdsd"; Solution sol; cout << "result: " << sol.strStr(haystack,needle) << endl; return 0; }