KMP算法实现strstr()函数

45 篇文章 0 订阅
21 篇文章 0 订阅
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++;
		else
			i = _next[i];

		if(i == pn)
			return s + j - i;
	}
	return NULL;
}
};


  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值