原题如下:
Returns a pointer to the first occurrence of needle in haystack, or null if needle is not part of haystack.
典型的字符串匹配问题,才知道原来C语言里还有这样的方法可供调用,好了,说实现。实现可以采取两种思路,其中一种思路称之为简单或者暴力解法,即从头遍历,当发现不匹配时折返进行重新匹配。奇怪的是这个思路的时间复杂度时O(M*N)但在leetcode上没有出现超时问题。
char *strStr1(char *haystack, char *needle) {
int len1 = strlen(haystack);
int len2 = strlen(needle);
for(int i = 0; i <= len1 - len2; i++){
char *p = haystack + i;
char *q = needle;
while(*q != '\0'){
if(*p != *q)
break;
p++;
q++;
}
if(*q == '\0')
return p - len2;
}
return NULL;
}
另外一种思路就是KMP解法了,这种解法在出现不匹配情况时不改变主串的位置,而是移动模式串,这样避免了一些无谓的比较。其比较过程如下:当模式串中第一个字符与主串不匹配或者模式串当前位置字符与主串字符匹配时,主串和模式串分别向后移动,当比匹配时,保持主串位置不变,而改变模式串的匹配位置j为当前节点的next[j]。从上述思路可以看出,KMP算法的关键是主串next[]的求解,而求解next的过程同样是一个模式串与自身的匹配问题,假设已知next[i] = j,那么如何求解next[i + 1]呢?这个问题分两种情况考虑:一是如果needle[i] == needle[j],那么next[i + 1] = j + 1,否则与上述匹配时的情况相同,让j = next[j].在求解next[]的过程中应该注意,当遇到next[j] = -1 时,其处理情况与匹配时的情况相同,都是next[++i] = ++j;,另外从该式也可以看出next[i +1]是由其前一个节点i的匹配情况决定的,所以遍历时不必遍历最后一个节点。
char *strStr(char *haystack, char *needle) {
int len1 = strlen(haystack);
int len2 = strlen(needle);
vector<int>next(len2,-1);
getNext(needle,next);
int i = 0, j = 0;
while(i < len1 && j < len2){
if(j == -1 || haystack[i] == needle[j]){
i++;
j++;
}
else
{
j = next[j];
}
}
if(j == len2)
return haystack + (i - j);
else
return NULL;
}
void getNext(char *needle,vector<int>&next){
int len = strlen(needle);
int i = 0,j = -1;
while(i < len - 1){
if(j == -1 || needle[i] == needle[j]){
next[++i] = ++j;
}
else
j = next[j];
}
}
KMP算法关键是要理解思路,其代码具体实现并不复杂,要注意匹配算法和求next[] 算法的异同,同时要注意初值i和j的设定。