KMP算法实现strstr()函数

来源:互联网 发布:火眼金睛 软件 编辑:程序博客网 时间:2024/05/22 04:47
strstr()函数是C语言库中的字符串匹配函数,函数搜索一个字符串在另一个字符串中的第一次出现。

其在标准库的函数原型为

const char * strstr ( const char * str1, const char * str2 );
           char * strstr (       char * str1, const char * str2 );

这是典型的字符串查找匹配问题。常用的方法有普通方法、KMP算法、BM算法、利用字典树等。

普通法:

普通法很直观,双重循环进行匹配,失配的时候就回溯回去重新匹配,时间复杂度为O(N^2)。下面给出了普通方法从右向左的匹配形式。

char *strStr(char *s, char *p) {int sn = strlen(s);int pn = strlen(p);int j = 0; //j指向母串int i; //j指向子串while(j <= sn - pn){for(i = pn - 1; i>=0 && p[i] == s[j+i]; --i);if(i < 0)return s + j; else++j;}return NULL;}


KMP方法:

众所周知,KMP算法的时间复杂度是O(N),因为其匹配过程中母串指针完全不需要回溯,一路向右。对于该算法,求解next数组是最关键的地方,用有限状态自动机的思想去理解KMP算法是一种非常好的思路。

对于有限状态机,一般来讲状态转换函数是一个二维数组:     A[当前状态值][输入值] = 下一状态值。

对于字符串匹配问题来说,可以将状态转换函数省略为一维数组 :  next[当前状态] = 下一状态值,     (其默认的输入值为匹配失败的输入,“状态值”就是已经匹配的字符个数。)
next数组只记录匹配失败时的状态转换。匹配成功的输入值是对应位置的字符,匹配成功的话状态值都是加1。


比如,子串“abaabcac”。

状态 0     1     2     3     4     5     6     7     8
字符 ∅    a     b     a     a     b     c     a     c


初始值
next[0]  = 0
next[1] = 0

递推关系
假设next[i] = j ,即i状态时的失配后的下一状态值是j。
这表明第1~第j的字符子串,等于,第i-j+1~第i的字符子串。
则,
    若p[j] == p[i],(第j+1字符等于第i+1字符),那么next[i+1] = next[i] + 1
    若p[j] != p[i],那么分析1~j子串内部,令j=next[j],重新判断p[j] == p[i]是否相等,直至判定到相等或者j为0。

class Solution {public:    char *strStr(char *haystack, char *needle) {        return _strStr(haystack, needle);  }    int _next[100000] = {0};    void getnext(char str[], int size){_next[0] = 0;_next[1] = 0;int i = 1, j = 0;for(;i<size-1;i++){j = _next[i];if(str[i] == str[j]){_next[i+1] = j + 1;}else{j = _next[j];while((str[i] != str[j]) && (j != 0) ){j = _next[j];}_next[i+1] = j;}}}char *_strStr(char *s, char *p){int sn = strlen(s);int pn = strlen(p);if(pn == 0)    return s;getnext(p, pn);int i=0,j=0;while(j < sn){if(p[i] == s[j]){i++;j++;}else if( i == 0)j++;elsei = _next[i];if(i == pn)return s + j - i;}return NULL;}};


0 0