Leetcode: strStr()
Implement strStr().
Returns the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack.
分析:该题是经典的串匹配,我们可以用KMP来解,时间复杂度为O(m+n)。关于KMP的详细内容可以参考一下博文http://www.cnblogs.com/dolphin0520/archive/2011/08/24/2151846.html。这里,我主要介绍一下运用KMP的几个关键点。
1. 为了避免指针回溯,KMP引入了next数组,用来确定下次匹配时模式串指针的位置。在用next数组前,我们要知道next[j]的含义,便于我们理解和实现。通俗的讲,next[j]表示pattern[0,j-1]中其前缀跟后缀相同的最大长度,我们用下面的式子来帮助理解:
next[0] = -1, next[1] = 0; for j > 1, next[j] = max(k) where 0<k<j and pattern[0,k-1] = pattern[j-k, j-1]。
2. 如何计算next数组,我们可以用动态规划的思想来计算next数组,在计算next[j]时,如果pattern[j-1] = pattern[next[j-1]],那么next[j] = next[j-1] + 1; 否则不匹配,则可以按KMP的做法,用next[j-1]确定下一个匹配的位置(此时模式串和目标串都是pattern[0,j-1])。
3. 在解决上面两个问题后,我们讨论如果通过next数组来做串匹配。在串匹配的时候可分两种情况:
1) target[i] = pattern[j],说明匹配,我们只需i++, j++。
2)target[i] != pattern[j], 此时我们需要用next数组确定j的下一个匹配位置。如果next[j] >= 0,则 j = next[j],i位置不便; 如果next[j] == -1,i往后移一步,j置0。
在实现时,2)中next[j] = -1的情况可以跟1)的情况合并。
解决了上面三个讨论,我们就可以写出KMP代码了,如下:
1 class Solution { 2 public: 3 char *strStr(char *haystack, char *needle) { 4 return kmp(haystack, needle); 5 } 6 char * kmp(char * haystack, char * needle){ 7 int m = strlen(needle); 8 if(m == 0) return haystack; 9 int * next = (int *)malloc(sizeof(int) * m); 10 11 compute_next(needle, next); 12 int i = 0, k = 0; 13 14 while(i < strlen(haystack)){ 15 if(k == -1 || haystack[i] == needle[k]){ 16 k++; 17 i++; 18 }else k = next[k]; 19 if(k == m) return haystack+i-m; 20 } 21 return NULL; 22 } 23 void compute_next(char * needle, int * next){ 24 int m = strlen(needle); 25 next[0] = -1; 26 int k = -1; 27 for(int j = 0; j < m-1;){ 28 if(k == -1 || needle[j] == needle[k]){ 29 k++; 30 j++; 31 next[j] = k; 32 }else k = next[k]; 33 } 34 } 35 };