KMP算法

KMP算法详解 文章目录KMP算法前置知识串的基本概念C++C++C++中stringstringstring库的函数KMP核心算法—next数组KMP匹配next数组计算例题KMP算法改进其他字符串知识点计算最长前缀后缀计算循环节补充字符使原字符串变为循环串 KMP算法 ​ KMPKMPKMP算法是字符串匹配中的一个较好的算法,它的目的是在给定一个模式串ppp和原字符串qqq中,找到ppp在qqq中第一次出现的位置。 ​ 如上图所示,可以很简单的看出字符串ppp在字符串qqq中第一次出现的位置,如果位置从1开始计算的话 阅读详情

下面来总结一下用来匹配字符串的KMP算法,以及怎么求next数组。

当然我们可以用笨办法可以进行字符串匹配和求next数组,但是学习算法不就是追求极致的过程么?

通过参考https://blog.youkuaiyun.com/sun20209527/article/details/79933237,可以通透的理解KMP是个什么过程,但细节处理和他会有些出入。

举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串"ABCDABD"?

  

 

我们先说一下next数组代表的是什么?就是一个字符串的每一个子串的前缀后缀的共有元素长度。

以"ABCDABD"为例,

  - "A"的前缀和后缀都为空集,共有元素的长度为0;

  - "AB"的前缀为[A],后缀为[B],共有元素的长度为0;

  - "ABC"的前缀为[A, AB],后缀为[BC, C],共有元素的长度0;

  - "ABCD"的前缀为[A, AB, ABC],后缀为[BCD, CD, D],共有元素的长度为0;

  - "ABCDA"的前缀为[A, AB, ABC, ABCD],后缀为[BCDA, CDA, DA, A],共有元素为"A",长度为1;

  - "ABCDAB"的前缀为[A, AB, ABC, ABCD, ABCDA],后缀为[BCDAB, CDAB, DAB, AB, B],共有元素为"AB",长度为2;

  - "ABCDABD"的前缀为[A, AB, ABC, ABCD, ABCDA, ABCDAB],后缀为[BCDABD, CDABD, DABD, ABD, BD, D],共有元素的长度为0。

所以next[0] = 0 ; next[1] = 1 ; next[2] = 0; next[3] = 0 ; next[4] = 1; next[5] = 2 ; next[6] = 0 ;

下面就是KMP的具体过程:

1.

     B与A不匹配,所以搜索词后移一位。

2.

  因为B与A不匹配,搜索词再往后移。

3.

  就这样,直到字符串有一个字符,与搜索词的第一个字符相同为止。

4.

这里出现了空格和D不匹配的现象.

5.

注意:这个操作一次连续移动了4位,我们把已经匹配的ABCDAB字符串的前缀移动到后缀的位置上就可以了!

6.

  因为空格与A不匹配,继续后移一位。

7.

一直匹配。。。。一直到发现C和D不匹配。

8.

已经匹配的字符串ABCDAB还是把最大的 前缀放到后缀的位置上。然后继续匹配ABCDAB后面的字符。

9.

  "部分匹配"的实质是,有时候,字符串头部和尾部会有重复。比如,"ABCDAB"之中有两个"AB",那么我们可以利用next数组记录的信息搜移动之后,就可以来到第二个"AB"的位置。

 

 

#include<iostream>
#include<cstring>
using namespace std;
void getnext(string s,int next[])
{
	int n = s.size();	
	memset(next,0,sizeof(next));
	int k = 0;                      //k代表 最大前后缀长度 
	for(int i = 1,k = 0; i<n; i++)
	{
		while(k>0 && s[k] != s[i])
		{
			k = next[k-1];	
		} 
		
		if(s[i] == s[k])
		{
			k++;
		}
		next[i] = k;
	}

	
}
 //a 是主字符串   b是小字符串 
int kmp(string a,string b,int next[])
{
	
	int n = a.size() , i = 0;           //主字符串的长度,主字符串的下标 
	int m = b.size() , j = 0;			//小字符串的长度,已经匹配的个数 
	
	while(i < n) 
	{
		
		if(j==0)                       //如果小字符串中的第一个元素没有找到与大字符串中有匹配的,那就寻找===  
		{
			if(a[i] == b[j])
			{
				j++;                                      //已经匹配的个数 
			}
			else
			{
				i++;									 //主字符串的 下标 
			}
		}else{                        //已经有匹配的了 
			if(a[i+1] != b[j])    //如果不下一个字符不相等,那就移动小字符串,这个过程操作起来就是更改小字符串的下标。 
			{
				j = next[j-1];
			}	
		
			if(a[i+1] == b[j])  //如果相等那就比较下一个字符 
			{
				i++;
				j++;
				
			 }
	}
		
	    if(j == m)                    //如果小字符串全比较完了,那就是全匹配了,完成! 否则大字符串中不存在 小字符串! 
			return i;                //这里返回小字符串在大字符串中最后匹配成功的字符的下标 
	}
	return 0;	
}

int main()
{
	int next[1000];
	string a = "BBC ABCDAB ABCDABCDABDE";

	string b = "ABCDABD";
	
	getNext(next,b);
	

	cout<<"kmp:"<<kmp(a,b,next)<<endl;	
}

这里的求next数组我们可以用笨办法枚举的方法如下:

void getNext(int next[],string s)
{
	memset(next,0,sizeof(next));
	for(int i=0; i<s.size(); i++)
	{
		int ans = 0;
		
		string str = s.substr(0,i+1);
		for(int j=0; j<str.size()-1; j++)
		{
			string str1 = str.substr(0,j+1);			
			string str2 = str.substr(str.size()-j-1,str.size());
			if(str1==str2)
			{
				ans = j+1;
			}
		
		}
		
		next[i] = ans;
	}
} 

 

这样很容易懂,和容易写出来,但是效率很慢!所以在网上找到了一个特别精简的方法!

void getnext(string s,int next[])
{
	int n = s.size();
	memset(next,0,sizeof(next));
	int k = 0;                                  //k代表 最大前后缀长度 
	for(int i = 1,k = 0; i<n; i++)
	{
		while(k>0 && s[k] != s[i])             //精髓!!!!
		{
			k = next[k-1];	
		} 
		
		if(s[i] == s[k])
		{
			k++;
		}
		next[i] = k;
	}

	
}

 

k代表的是前一个字符串最长的前后缀长度 ; a[i]是新加上的字符

这里分几种情况:

1、如果s[0]......s[k-1]和s[i-k].......s[i-1]匹配,并且s[i] == s[k] ,那么next[i] = next[i-1]+1就可以了(简单的情况)

2、但是如果s[i] != s[k]呢?就是上面的标记精简的那段代码!

我们应该利用已经得到的next[0]···next[k-1]来求s[0]···s[k-1]这个子串中最大相同前后缀。因为!!在于s[k]已经和s[i]失配了,而且s[i-k] ··· s[i-1]又与s[0] ···s[k-1]相同,看来s[0]···s[k-1]这么长的子串是用不了了,那么我要找个同样也是s[0]打头、s[k-1]结尾的子串即s[0]···s[j-1](j==next[k-1]),看看它的下一项s[j]是否能和s[i]匹配。

用我们一个例子把:

ABADABA[B]

我们已经知道了 ABADABA的 next[6] = 3,也就是k=3,但是s[3]=D不等于s[7]=B,k= next[k-1] = next[2] =  1,再来比较s[1]和s[i],结果相等,那么next[7]=next[1]+1 = 2;

 

【KMP算法详解——适合初学KMP算法的朋友】 KMP算法的初级体验,只为抛砖引玉之用 阅读详情

相关推荐

Sonatype nexus3 数据迁移及升级3.71+(迁移到H2数据库)

nexus3旧版本OrientDB升级H2,及整体迁移nexus3数据到其它服务器。

葫芦娃 5555

图解算法:KMP算法

目录第一章 暴力匹配实现第二章 KMP算法介绍第三章 KMP算法原理第四章 KMP的匹配表第五章 KMP算法实现 项目地址:https://gitee.com/caochenlei/algorithms 第一章 暴力匹配实现 【问题描述】 有一个字符串 str1 = “BBC ABCDAB ABCDABCDABDE”,和一个子串 str2 = “ABCDABD”,现在要判断 str1 是否含有 str2,如果存在,就返回第一次出现的位置,如果不存在,就返回-1。 【问题思路】 【代码实现】 publ

轻松的小希 8311

4D毫米波雷达点云可视化实战:从CANFD原始数据到Matplotlib三维动态图

本文详细介绍了4D毫米波雷达点云可视化实战,从CANFD原始数据解析到Matplotlib三维动态图实现的全流程。通过解析CANFD数据帧结构、点云数据编码原理,并结合Python实现CANFD通信接口,帮助开发者掌握4D雷达数据处理与优化技巧,最终实现高性能的3D点云动态可视化。

u9v0w的博客 568

kmp算法总结

搞ACM也有三年了,期间学习了不少算法,到12月把上海站打完也要成退役狗了。最近突然想把学过的一些算法回过头来好好总结一下,于是就有了我的算法总结系列。这是这个系列的开端,所以先写一个简单点的算法,以后会慢慢复习一些复杂的算法,最后还是希望自己能够坚持下去吧。 KMP算法 KMP算法是一种线性时间复杂度的字符串匹配算法,它是对BF(Brute-Force,最基本的字符串匹配算法)的改进。对

ddyyxx的程序员之路 1万+

鸿蒙读书笔记1:《鸿蒙操作系统设计原理与架构》

GUI、 语 音 控 制 方 式 的 VUI(Voice User Interface, 语 音 用 户 界。电话、多媒体、DFX、MSDP(Multimodal Sensor Data Platform,多。面)、手势/姿态控制的CVUI(Computer Vision User Interface,计算。KAL(Kernel Abstract Layer,内核抽象层)通过屏蔽多内核差异,JavaScript、C、C++等多语言的用户程序开发框架,以及UI框架、

jackyrongvip的专栏 2451

Robosuite与Robomimic:机器人学习的黄金搭档

本文深入探讨了Robosuite与Robomimic这对机器人学习的黄金组合,详细介绍了如何利用Robosuite进行物理仿真和任务环境构建,以及Robomimic在演示数据处理和离线学习算法实现中的应用。通过实际案例和代码示例,展示了从仿真环境搭建到模型训练的全流程,帮助研究人员高效开展机器人学习实验。

weixin_29178069的博客 415

kmp算法详解

从头到尾彻底理解KMP 此文转自神的博客  http://blog.youkuaiyun.com/v_july_v/article/details/7041827# 作者:July 时间:最初写于2011年12月,2014年7月21日晚10点 全部删除重写成此文,随后的半个多月不断反复改进。后收录于新书《编程之法:面试和算法心得》第4.4节中。 1. 引言     本KMP原文最初写于2

楠先生 4万+

若依前后端分离版集成nacos

服务动态配置与服务注册发现根据公司要求,需要将项目集成到nacos中,当前项目是基于若依前后端分离版开发的,若依的版本为3.8.3,若依框架中整合的springBoot版本为2.5.14。Nacos核心提供两个功能:服务注册与发现,动态配置管理。

NDF923的专栏 4645

大话 KMP 算法

LeetCode上有一题,简单难度的,以下是原题 这个题目应该刷LeetCode的同学大部分都刷到过,比较荒谬的是可以直接用 indexOf 方法实现,并且是最优的解法,看到评论以后一片哗然,大家扯到最多的是这道题就应该用KMP来做,如果用KMP做那这道题应该是困难级别的。所以看了这些评论以后,决定自己去摸索一下KMP的算法,以及大概其实现原理。 网上找了很多关于解释KMP算法的...

lmx125254的博客 3833

SKUA-GOCAD入门教程-第七节 点的创建与编辑3

本文介绍了四种从井数据创建点集的方法

江洋大葱的博客 963

PLSQL Developer安装详细步骤

一、下载安装PLSQL Developer(plsql安装百度也有步骤) 官网下载地址:https://www.allroundautomations.com/registered-plsqldev/ 1、网上自己下载适合自己电脑的安装包(32或64),并解压。 2、打开解压的文件夹,得到以下三个文件(分别是汉化工具,PLSQL安装包、激活码),双击安装,如下图: 3、安装界面,点击next,进入下一步,如图: 4、安装协议界面,此处必须选择“I accept the terms in

Gorden的博客 11万+

kmp算法和kmp的优化

一、kmp是什么 KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法)。KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是通过一个next()函数实现,函数本身包含了模式串的局部匹配信息。KMP算法的时间复杂度O(m+n)。 简单来...

harry12138小白的博客 1498

Python爬虫实战:微信小程序内容采集的全面指南

在移动互联网时代,微信小程序已成为企业和个人提供服务的重要渠道。小程序中包含了大量有价值的信息,但微信官方并未提供便捷的数据获取接口。本文将详细介绍如何使用Python爬虫技术采集微信小程序内容,包括最新技术方案、完整代码实现以及应对各种反爬机制的策略。小程序运行在微信封闭环境中,无法直接访问数据通信主要通过HTTPS加密传输内容动态加载,依赖JavaScript渲染微信有严格的反爬机制。

2201_76125261的博客 3117

KMP及KMP改进算法

kmp”看毛片“算法确实很难理解,上网搜了半天想了很久才大概想明白。KMP算法精华在于next数组: "部分匹配值"即next数组就是"前缀"和"后缀"的最长的共有元素的长度。以"ABCDABD"为例, 首先看看 next 数组值的求解方法 。             例如:   模式串 abaabcac      next 值 01122312      ne

memmorryy的专栏 1446

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

【算法】KMP 算法

本文介绍字符串的模式匹配算法之一——KMP 算法,包括其概述、代码实现等。

代码星辰的博客 1448

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

算法 kmp算法

kmp算法是改进后的字符匹配算法,它与bf算法的区别是,每次从串与主串匹配失败后,从串与主串匹配的位置不同。下面具体说下这两种算法的区别:主串:BABCDABABCDABCED从串:ABCDABCEDBF算法:第一步:BABCDABABCDABCEDA               从主串的第一个字符位置开始与从串第一个字符位置进行匹配,匹配失败第二步:BABCDABABCDABCED ABCDAB...

夜雨柠檬 833

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

KMP算法啊啊啊

KMP算法问题引入串引子串的存储顺序存储结构链式存储结构问题来了直观解决方案KMP算法前言next数组KMP算法改进 问题引入 串 引子 我们在生活中可以看到很多的所谓“串”,比如现在我写的这段话就是“串”,更多的,比如我们在网上查找资料,如下图: "KMP"就是一个字符串,而每次我们所搜所完之后界面显示带红色的字就是与之匹配的串,其实就是在一个串中找与之匹配的字串,我感觉搜索的想法很简单:我呈...

xwl666666的博客 3608

kmp算法

假设有两个字符串S和P我们需要从字符串S中找到字符串P,并给出具体下标首先定义两个下标变量 i、 j先模拟一下kmp的核心之处下标 i 指向 a 开始进行匹配直到指向 c 的时候,这时候发现 值不一样了,需要重新进行匹配,但是实际情况是,下标 j 不需要退那么多,下标 j 只需要退到 第一个b字母处(j+1为第二个a字母处)原因是kmp算法当中,会有一个ne数组,用于记录匹配不成功后,下标 j 退的最少的坐标ne数组的长度和 被找的字符串的长度一样比如刚才的 a b a b e。

shallrelow的博客 786
上一篇: 【JVM之一入门】内存区域简介
下一篇: 【JVM之三】String与intern()方法
Joined
博客等级 码龄10年 19粉丝 134原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值