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代码了,如下:
class Solution {
public:
char *strStr(char *haystack, char *needle) {
return kmp(haystack, needle);
}
char * kmp(char * haystack, char * needle){
int m = strlen(needle);
if(m == ) return haystack;
int * next = (int *)malloc(sizeof(int) * m); compute_next(needle, next);
int i = , k = ; while(i < strlen(haystack)){
if(k == - || haystack[i] == needle[k]){
k++;
i++;
}else k = next[k];
if(k == m) return haystack+i-m;
}
return NULL;
}
void compute_next(char * needle, int * next){
int m = strlen(needle);
next[] = -;
int k = -;
for(int j = ; j < m-;){
if(k == - || needle[j] == needle[k]){
k++;
j++;
next[j] = k;
}else k = next[k];
}
}
};