首页 > 编程语言 >【KMP算法】

【KMP算法】

时间:2024-11-07 12:44:16浏览次数:4  
标签:BF sub int next 算法 KMP

目录

BF算法

KMP算法


BF算法

F算法,即暴力(Brute Force)算法,是普通的模式匹配算法,BF算法的思想就是将目标串S的第一个字符与模式串T的第一个字符进行匹配,若相等,则继续比较S的第二个字符和 T的第二个字符;若不相等,则比较S的第二个字符和T的第一个字符,依次比较下去,直到得出最后的匹配结果。BF算法是一种蛮力算法。                                              ----这段话来自百度百科。
这段话晦涩难懂,需要例子支持。下面我们就通过例子来解释这个问题。
假定我们给出字符串 ”ababcabcdabcde”作为主串, 然后给出子串: ”abcd”,现在我们需要查找子串是否在主串中出现,出现返回主串中的第一个匹配的下标,失败返回-1 ;

只要在匹配的过程当中,匹配失败,那么:i回退到刚刚位置的下一个,j回退到0下标重新开始。

 

对应C代码:

/**
Author:高博
Date:2021-08-02 21:54
str:主串
sub:子串
*/
int BF(char *str,char *sub)
{
assert(str != NULL && sub != NULL);
if(str == NULL || sub == NULL)
{
return -1;
}
int i = 0;
int j = 0;
int strLen = strlen(str);
int subLen = strlen(sub);
while(i < strLen && j < subLen)
{
if(str[i] == sub[j])
{
i++;
j++;
}
else
{
//回退
i = i-j+1;
j = 0;
}
}
if(j >= subLen)
{
return i-j;
}
return -1;
}
int main()
{
printf("%d\n",BF("ababcabcdabcde","abcd"));
printf("%d\n",BF("ababcabcdabcde","abcde"));
printf("%d\n",BF("ababcabcdabcde","abcdef"));
return 0;
}

 对应java代码:

/**
* Created by GAOBO
* Description:
* User: GAOBO
* Date: 2021-08-02
* Time: 22:05
*/
public class Test {
public static int BF(String str,String sub) {
if(str == null || sub == null) return -1;
int strLen = str.length();
int subLen = sub.length();
int i = 0;
int j = 0;
while (i < strLen && j < subLen) {
if(str.charAt(i) == sub.charAt(j)) {
i++;
j++;
}else {
i = i-j+1;
j = 0;
}
}
if(j >= subLen) {
return i-j;
}
return -1;
}
public static void main(String[] args) {
System.out.println(BF("ababcabcdabcde","abcd"));
System.out.println(BF("ababcabcdabcde","abcde"));
System.out.println(BF("ababcabcdabcde","abcdef"));
}
}

时间复杂度分析:最坏为O(m*n); m是主串长度,n是子串长度 

KMP算法

KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法)。KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是通过一个next()函数实现,函数本身包含了模式串的局部匹配信息。KMP算法的时间复杂度O(m+n) [1]  。 来自-------百度百科。
区别:KMP 和 BF 唯一不一样的地方在,我主串的 i 并不会回退,并且 j 也不会移动到 0 号位置
1 .首先举例,为什么主串不回退?

2 .j的回退位置

引出next数组
KMP 的精髓就是 next 数组:也就是用 next[j] = k;来表示,不同的 j 来对应一个 K 值, 这个 K 就是你将来要移动的 j要移动的位置。
而 K 的值是这样求的:


1、规则:找到匹配成功部分的两个相等的真子串(不包含本身),一个以下标 0 字符开始,另一个以 j-1 下标字符结尾。
2、不管什么数据 next[0] = -1;next[1] = 0;在这里,我们以下标来开始,而说到的第几个第几个是从 1 开始;

求next数组的练习:


练习 1: 举例对于”ababcabcdabcde”, 求其的 next 数组?
-1 0 0 1 2 0 1 2 0 0 1 2 0 0
练习 2: 再对”abcabcabcabcdabcde

”,求其的 next 数组? "
-1 0 0 0 1 2 3 4 5 6 7 8 9 0 1 2 3 0
到这里大家对如何求next数组应该问题不大了,接下来的问题就是,已知next[i] = k;怎么求next[i+1] = ?如果我们能够通过 next[i]的值,通过一系列转换得到 next[i+1]得值,那么我们就能够实现这部分。
那该怎么做呢?
首先假设: next[i] = k 成立,那么,就有这个式子成立: P0...Pk-1 = Px...Pi-1;得到: P0...Pk-1 = Pi-k..Pi-1;到这一步:我们再假设如果 Pk = Pi;我们可以得到 P0...Pk = Pi-k..Pi;那这个就是 next[i+1] = k+1; 

那么: Pk != Pi 呢?
看如下实例:

 c语言代码:

void GetNext(int *next,const char *sub)
{
int lensub = strlen(sub);
next[0] = -1;
next[1] = 0;
int i = 2;//下一项
int k = 0;//前一项的K
while(i < lensub)//next数组还没有遍历完
{
if((k == -1) || sub[k] == sub[i-1])//
{
next[i] = k+1;
i++;
k++;//k = k+1???//下一个K的值新的K值
}
else
{
k = next[k];
}
}
}
int KMP(const char *s,const char *sub,int pos)
{
int i = pos;
int j = 0;
int lens = strlen(s);
int lensub = strlen(sub);
int *next = (int *)malloc(lensub*sizeof(int));//和子串一样长assert(next != NULL);
GetNext(next,sub);
while(i < lens && j < lensub)
{
if((j == -1) || (s[i] == sub[j]))
{
i++;
j++;
}
else
{
j = next[j];
}
}
free(next);
if(j >= lensub)
{
return i-j;
}
else
{
return -1;
}
}
int main()
{
char *str = "ababcabcdabcde";
char *sub = "abcd";
printf("%d\n",KMP(str,sub,0));
return 0;
}

java算法代码:

public static void getNext(int[] next, String sub){
next[0] = -1;
next[1] = 0;
int i = 2;//下一项
int k = 0;//前一项的K
while(i < sub.length()){//next数组还没有遍历完
if((k == -1) || sub.charAt(k) == sub.charAt(i-1)) {
next[i] = k+1;
i++;
k++;
}else{
k = next[k];
}
}
}
public static int KMP(String s,String sub,int pos) {
int i = pos;
int j = 0;
int lens = s.length();
int lensub = sub.length();
int[] next= new int[sub.length()];
getNext(next,sub);
while(i < lens && j < lensub){
if((j == -1) || (s.charAt(i) == sub.charAt(j))){
i++;
j++;
}else{
j = next[j];
}
}
if(j >= lensub) {
return i-j;
}else {
return -1;
}
}
public static void main(String[] args) {
System.out.println(KMP("ababcabcdabcde","abcd",0));
System.out.println(KMP("ababcabcdabcde","abcde",0));
System.out.println(KMP("ababcabcdabcde","abcdef",0));
}

next数组的优化

next 数组的优化,即如何得到 nextval 数组:有如下串: aaaaaaaab,他的 next 数组是-1,0,1,2,3,4,5,6,7.而修正后的数组 nextval 是:
-1, -1, -1, -1, -1, -1, -1, -1, 7。为什么出现修正后的数组,假设在 5 号处失败了,那退一步还是a,还是相等,接着退还是 a。
练习:模式串 t=‘abcaabbcabcaabdab’ ,该模式串的 next 数组的值为( D ) , nextval 数组的值为 (F)。
A. 0 1 1 1 2 2 1 1 1 2 3 4 5 6 7 1 2 B. 0 1 1 1 2 1 2 1 1 2 3 4 5 6 1 1 2
C. 0 1 1 1 0 0 1 3 1 0 1 1 0 0 7 0 1 D. 0 1 1 1 2 2 3 1 1 2 3 4 5 6 7 1 2
E. 0 1 1 0 0 1 1 1 0 1 1 0 0 1 7 0 1 F. 0 1 1 0 2 1 3 1 0 1 1 0 2 1 7 0 1

 

标签:BF,sub,int,next,算法,KMP
From: https://blog.csdn.net/weixin_73861555/article/details/143591369

相关文章

  • α-shape算法曲面重建
    目录1原理介绍α-shape的基础概念数学公式推导2.1外接圆半径2.2根据α参数筛选三角形2.3构建α-shape2.4参数调整与优化3α-shape的构建步骤4示例代码        取点云的凹边界是计算几何中的一个经典问题。凹边界与凸边界不同,它能捕捉到数据的细......
  • Java深度优先搜索(DFS)算法实现
    标题:Java深度优先搜索(DFS)算法实现引言:深度优先搜索(Depth-FirstSearch,DFS)是一种常用的图遍历算法,它通过递归地遍历图中的每个顶点,来寻找特定的路径或解决某些问题。本篇博客将介绍如何用Java语言实现深度优先搜索算法。算法思想:深度优先搜索算法的基本思想是先访问一个......
  • c++ Kruskal 最小生成树 (MST) 算法(Kruskal’s Minimum Spanning Tree (MST) Algorith
            对于加权、连通、无向图,最小生成树(MST)或最小权重生成树是权重小于或等于其他所有生成树权重的生成树。Kruskal算法简介:        在这里,我们将讨论Kruskal算法来查找给定加权图的MST。         在Kruskal算法中,按升序对给定图的所有......
  • 常考的排序算法
    冒泡排序#include<iostream>#include<string>usingnamespacestd;//voidShellsort(intA[],intn)//{//   intd,i,j;//   for(d=n/2;d>=1;d=d/2)//   {//      for(i=d+1;i<=n;i++)//      {//     ......
  • JavaScript Kruskal 最小生成树 (MST) 算法(Kruskal’s Minimum Spanning Tree (MST) A
             对于加权、连通、无向图,最小生成树(MST)或最小权重生成树是权重小于或等于其他所有生成树权重的生成树。Kruskal算法简介:        在这里,我们将讨论Kruskal算法来查找给定加权图的MST。         在Kruskal算法中,按升序对给定图的所......
  • 基于springboot框架在线生鲜商城推荐系统 java实现个性化生鲜/农产品购物商城推荐网站
    基于springboot框架在线生鲜商城推荐系统java实现个性化生鲜/农产品购物商城推荐网站爬虫、数据分析、排行榜基于协同过滤算法推荐、基于流行度热点推荐、平均加权混合推荐机器学习、大数据、深度学习OnlineShopRecommendEx一、项目简介1、开发工具和使用技术IDEA,jdk......
  • 【算法学习】反悔贪心
    前言反悔贪心,先选择局部最优,当不断向后更新时发现前面的决策在现在来看并不优就进行调整过去决策进行局部最优,可以说反悔贪心一步步扩宽自己的视野从而明白过去的错误。、如果动态规划是将各种削苹果的方式都展示出来的话,那反悔贪心就是削一下补回来一点再削。当然反悔贪心的题......
  • C语言数据结构--详细讲解算法复杂度
    C语言数据结构-算法复杂度前言一、时间复杂度1.大O渐进表示法2时间复杂度的计算二、空间复杂度1.什么是空间复杂度2时间复杂度的计算总结前言我们都清楚计算机存储和组织数据是通过数据结构来实现的。当计算机对这些数据结构中的数据进行遍历等操作时,这个过程就......
  • 代码随想录算法训练营第十八天|leetcode530.二叉搜索树的最小绝对差、leetcode501.二
    1leetcode530.二叉搜索树的最小绝对差题目链接:530.二叉搜索树的最小绝对差-力扣(LeetCode)文章链接:代码随想录视频链接:你对二叉搜索树了解的还不够!|LeetCode:98.验证二叉搜索树_哔哩哔哩_bilibili思路:定义一个极大值作为结果,然后在中序遍历过程中进行比较出结果1.1自己的......
  • 算法笔记——马拉核弹(Mana Nuclear)
    0x00摘要“马拉核弹”算法由SXHT同学(2009~今)发明,并在2024年11月于某不知名学校机房内正式公布。该算法基于1975年发明的Manacher算法,并将其推广至对称正方形问题。原文链接与密码:sunxuhetai2009。关键词:Manacher算法信息学对称正方形0x01缘由先来看这道题目:......