算法 | KMP算法

核心:主串不能回退,一直遍历
当子串没有重复的时候子串回退到头部
有重复的时候回退到最后一个重复位置

如果发生失配,从失配位置向前看,看字串是否存在两个真子串一个顶头一个顶尾

匹配到c的时候匹配失败,按照普通方式是子串回到起始位置,主串到上次开始匹配位置的下一个位置,也就是b,但是这样的话在匹配失败的位置c的前面等于发生"错位",在这里插入图片描述

这样错位一直到在这里插入图片描述
,这时候其实也是错位,但是刚好错位还跟第一次匹配错误位置前两个对应上了,由于并不知道第一次匹配错误的位置是否等于子串的下一个位置,所以需要比较一下b是否和a相等
这种过程其实浪费了许多时间,**假如失配位置前没有和子串头相等的,子串在失配位置前的移动都是明确知道结果的,那就是一直失配,**直到第一次失配位置才是未知的,所以要找一种方法让他略过确定失配的位置,直接到匹配结果未知的位置
看图可发现失配位置前和子串头有相等的地方可以直接比较失配位置和子串相等位置的下一个

所以要做一个表用来记录应该跳到子串的位置即前缀

如何求前缀

看字串是否存在两个真子串一个顶头一个顶尾
在这里插入图片描述

比如abcdab当最后一位发生失配,则下标应当跳转到下标1,即第二位,因为下标0已经匹配了,此时只需要第二位和主串当前比较即可,因为主串的前一位一定是a,不然也不会匹配到最后一位,每一位应当储存当前位之前和字符串从头往前看有几位匹配(不包括当前位,因为0下标的存在正好可以当当前位要比较的位置),注意,这里"当前位之前"并不是相向,而是相同方向看
在这里插入图片描述

		vector<int> prefix(n_len + 1);

		prefix[0] = -1;

		int i = 0;
		int j;
		while (i < n_len)
		{
			j = prefix[i];
			while (j != -1 && needle[j] != needle[i])
			{
				j = prefix[j];
			}
			//至此,needle[j]要么跟needle[i]相等,要么是-1,告诉下一位要比较的位是j+1
			prefix[i + 1] = j + 1;
			++i;
		}

完整代码

class Solution {
public:
	int strStr(string haystack, string needle) {
		int n_len = needle.size();
		int h_len = haystack.size();
		vector<int> prefix(n_len + 1);

		prefix[0] = -1;

		int i = 0;
		int j;
		while (i < n_len)
		{
			j = prefix[i];
			while (j != -1 && needle[j] != needle[i])
			{
				j = prefix[j];
			}
			//至此,needle[j]要么跟needle[i]相等,要么是-1,告诉下一位要比较的位是j+1
			prefix[i + 1] = j + 1;
			++i;
		}

		for (i = 0, j = 0; i < h_len; ++i)
		{
			while (j!=-1 && haystack[i] != needle[j])
			{
				j = prefix[j];
			}
			if (j == -1||haystack[i] == needle[j])
			{
				j += 1;
			}
			if (j == n_len) return i - j + 1;
		}
		return -1;

	}
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值