KMP算法详解

原理详解

KMP算法的作用是在一个已知字符串中查找子串的位置,也叫做串的模式匹配。比如主串s=“goodgoogle”,子串t=“google”。现在我们要找到子串t 在主串s 中的位置。
第一种我们容易想到的就是暴力求解法。
这种方法也叫朴素的模式匹配:

简单来说就是:从主串s 和子串t 的第一个字符开始,将两字符串的字符一一比对,如果出现某个字符不匹配,主串回溯到第二个字符,子串回溯到第一个字符再进行一一比对。如果出现某个字符不匹配,主串回溯到第三个字符,子串回溯到第一个字符再进行一一比对一直到子串字符全部匹配成功。

这种算法在最好情况下时间复杂度为O(n)。即子串的n个字符正好等于主串的前n个字符,而最坏的情况下时间复杂度为O(m*n)。相比而言这种算法空间复杂度为O(1),即不消耗空间而消耗时间。

详细原理参考:KMP算法配图详解

对于nextval矩阵,如果第a位字符与它next值指向的第b位字符相等,则该a位的nextval就指向b位的nextval值,如果不等,则该a位的nextval值就是它自己a位的next值。

c++代码实现

#include<iostream>
#include<vector>
using namespace std;

class KMP {
public:
	void Next(string data,vector<int>&next) {
		int i = 0, j = -1;
		next[0] = -1;//next数组第一个值为-1
		while (i < data.size()-1) {
			if (j == -1 || data[i] == data[j]) {
				i++;
				j++;
				next[i] = j;
			}
			else j = next[j];
		}
	}
	void NextVal(string data, vector<int>& next) {
		int i = 0, j = -1;
		next[0] = -1;
		while (i < data.size() - 1) {
			if (j == -1 || data[i] == data[j]) {
				i++;
				j++;
				if (data[i] != data[j])next[i] = j;
				else next[i] = next[j];
			}
			else j = next[j];
		}
	}
	int kmpFind(string data,string son) {
		int idx_data = 0;//data的当前下标
		int idx_son = -1;//son的当前下标
		vector<int> next(son.size(), 0);//next数组
		//this->Next(son, next);//求得next数组
		this->NextVal(son, next);
		//string.size()是unsigned int类型,直接判断会导致(int)-1 > (unsigned)3
		while (idx_data < (int)data.size() && idx_son < (int)son.size()) {
			//两字符相等时继续
			if (idx_son == -1 || data[idx_data] == son[idx_son]) {
				idx_data++;
				idx_son++;
			}
			//指针后退开始重新匹配,j回退到合适位置,i不需要动
			else idx_son = next[idx_son];
		}
		if (idx_son >= son.size()) return idx_data - son.size();
		else return 0;
	}
};

int main() {
	KMP k;
	string s1 = "dsadsadsaadsadsa";
	string son = "dsa";
	int a = k.kmpFind(s1, son);
	cout << a << endl;
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值