首页 > 编程语言 >字符串匹配(BP&KMP算法)

字符串匹配(BP&KMP算法)

时间:2025-01-15 12:31:49浏览次数:3  
标签:子串 匹配 int next 算法 BP KMP

BP&KMP算法

字符串匹配

前言

本文是基于懒猫老师的课程----BP&KMP所写,在观看本文之前最好配合视频或者PPT食用更佳,地址我附在下面:
https://www.bilibili.com/video/BV1EE411378s?spm_id_from=333.788.videopod.sections&vd_source=3daecc9000cbc58a3bc39bf941c4d208
https://www.bilibili.com/video/BV1U7411f7CB?spm_id_from=333.788.videopod.sections&vd_source=3daecc9000cbc58a3bc39bf941c4d208

BP算法(基础)

BF算法的原理
BF算法其实是比较简单的,这两个算法都是用于字符串匹配
比如给定一个主串 S,一个模式串T又称为子串
在子串和主串比较的过程中 每当子串与主串的元素相同时i++,J++,直到出现了不同的元素时,主串和子串的指针进行回溯,主串指针i回溯到i+1(i-j+1)的位置上,子串回溯到0的位置上,其实从图像上看就是子串相对于主串向前移动了一个位置,即从现在主串的新的i位置进行重新匹配,直到匹配成功跳出循环,即循环条件为i!=[\0]&&j!=[\0],结束循环后说明i和j至少有一个到了末尾即遍历完毕,这时候做一个if-else判断即可,成功返回起始下标,否则返回-1即可,

引文

其实我们在观看懒猫老师课上的动画演示以及计算完BF的时间复杂度后,我总感觉很多次比较是没有必要的,从而浪费了很多时间,但事实的确是这样的,这一点后续会给出具体分析,第二就是我们发现每一次匹配不成功时就需要大量回溯,没有利用已经部分匹配的结果
那么我们怎样解决这些问题呢,而下面的KMP算法其实就是BF算法的进阶,它本质上是基于BF算法的思想并借助next数组对代码进行了修改,但却很好的解决了这些问题

KMP算法(进阶)

KMP算法与BF算法最大的不同就是在于“失配”情况的处理,即在遇见字符不匹配时,在KMP算法主串不会进行回溯即保持不变,而子串会向前滑动一段距离,这个滑动的距离怎么确定呢(难点)
首先我们要明确当我们的主串不回溯时,我们既要达成我们匹配字符串的目标,也要尽可能的提高效率(滑动距离的确定),这时我们的子串最多移动到发生失配位置前面而不能移动到失配位置之后(会有遗漏)

在这里插入图片描述

我们怎样理解计算滑动距离的公式呢?
已匹配字符数就是失配位置前的字符数量(匹配成功的字符数),最长前缀匹配字符数可以借助PPT来理解,比如这里失配位置之前最长的是ab,长度为2,所以滑动距离就是6-2=4。

算法总结:
在这里插入图片描述

这个“滑动”虽然在图像上看着容易,但是当我们的字符串比较长时需要滑动的次数就越来越多,用一个普适性的代码,来实现这个公式以及把握一些细节的处理是比较难的,我们需要用next数组来计算(存储失配位置前)(最长前缀匹配字符数)(重难点),从而帮助我们实现KMP的伪代码,
在大致了解KMP算法的大致思想后 首先我们还是先分析前文提到的问题“对于滑动过程中所略去的字符真的全部都可以不比较吗”
因为我们在准备滑动之前已经比较失配位置了前面的所有字符,例如在下图第二趟中,我们为什么可以不比较a和b呢,因为在第一趟的时候我们知道(主串第二个元素b)=(子串的第二个元素b),即T[1]=S[1]而T[1]!=T[0],则T[0]!=S[1],接下来同理,直到“e”前面的“ab”,因为此时子串的第一个元素发生了重现,即出现了前缀后缀相等的情况,这个时候我们就需要将子串滑动到此处重新执行比较操作,一直这样持续下去。

在这里插入图片描述

伪代码描述

在这里插入图片描述

next数组递归求解思路

首先我觉得这个算法虽然简短,但是确实很难理解的,需要所谓的数形结合的方式来帮助我们去弄懂,给我的感觉就像是在动态的去解决问题 代码如下:

//next数组
//这个算法其实是比较难以理解的 需要借助图像
void getNext(char *T,int *next)
{
    int j=-1;//j代表前缀,i代表后缀
    int i=0;
    next[0]=-1;
    int length= strlen(T);
    while (i<length)
    {
    if(j==-1 ||T[i]==T[j])
    {
        i++;
        j++;
        next[i]=j;//
    } else{
        j=next[j];
    }
    }
}

算法思路详解

我们得明确next数组到底需要去做什么以及明白它的原理(非常重要)
对于下面的图片中,我们已知A1和A2相等,这里的相等不仅是长度还有值也是相等的,而我们的目的是找到失配位置前的最匹配的前缀后缀长度,那么我们还需要去往后继续比较,看看是不是还相等,那么j在这里表示前缀,i表示后缀,而T[j]正好就表示A1后面的元素,所以我们就还需要比较T[i]和T[j],
如果相等那么i和j就需要向后移动,此时我们将j的值++后填入我们i++后的位置上,而这时填入的j++后的值就是我们目前找到的最大长度

在这里插入图片描述
上面的情况我们分析完毕,我们回到原先的判断语句,如果不相等(难点),那么就是说明A1和A2就【失效】了,我们需要退而求其次,我们需要考虑图中A1,A2之外最长的B1,B2,那么我们的前缀j的位置自然就需要回溯到之前类似的情况,只不过这时候j的前面,我们已知的是B1=B2,B1和B2是作为此时的回溯后j(上一次循环后填入的结果)的前缀后缀出现的,但是由于一开始我们知道A1=A2,而B1和B3都是其各自的子串,那么我们就可以得出B1=B2=B3,那么这时只需要将已知相等的B1和B3进行比较,也就是又返回到了上面一种情况,如此往复,可以说是非常巧妙了
在这里插入图片描述

KMP算法实现及测试(先做在看!)

//KMP算法
int KMP (char *S, char *T,int * next)
{
    int i=0;
    int j=0;
    int lenS= strlen(S);
    int lenT= strlen(T);
    while (i<lenS && j<lenT)
        //这里为什么没有用while(S[i] != '\0' && T[j] != '\0')呢,
        // 因为 当j为-1的时候数组会发生越界
    {
        if(j==-1 || S[i]==T[j])
        {
            i++;
            j++;
        } else{
            j=next[j];
        }
    }
    if(j==lenT)
    {
        return i-j;
    } else{
        return -1;
    }
}
int main() {
    char S[] = "DABASHUASH";
    char T[] = "AS";
    int result = BP(S, T);
    printf("Result: %d\n", result);
    int next[10];
    getNext(T,next);
    int result2= KMP(S,T,next);
    printf("Result: %d\n", result2);
    return 0;
}

标签:子串,匹配,int,next,算法,BP,KMP
From: https://blog.csdn.net/2402_88307286/article/details/145155481

相关文章

  • ISP基本框架及算法介绍
    ISP(ImageSignalProcessor),即图像处理,主要作用是对前端图像传感器输出的信号做后期处理,主要功能有线性纠正、噪声去除、坏点去除、内插、白平衡、自动曝光控制等,依赖于ISP才能在不同的光学条件下都能较好的还原现场细节,ISP技术在很大程度上决定了摄像机的成像质量。它可以分......
  • 科普文:算法和数据结构系列【压缩和通信利器:哈夫曼树(Huffman Tree)java示例代码解读】
    概叙科普文:算法和数据结构系列【算法和数据结构概叙】-CSDN博客科普文:算法和数据结构系列【非线性数据结构:树Tree和堆Heap的原理、应用、以及java实现】-CSDN博客科普文:算法和数据结构系列【树:4叉树、N叉树】-CSDN博客科普文:算法和数据结构系列【二叉树总结-上篇:满二叉树、......
  • 算法-移除元素
     力扣题目:27.移除元素-力扣(LeetCode)给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。假设 nums 中不等于 val 的元素数量为 k,要通过此题,您需要执行以下操作......
  • 【轻松掌握数据结构与算法】字符串算法(String Algorithms)
    字符串算法概述字符串匹配算法是计算机科学中的一个重要领域,主要用于在文本中查找特定模式(子字符串)的出现位置。这些算法在文本编辑器、搜索引擎、生物信息学等领域有广泛的应用。暴力法(BruteForceMethod)暴力法是最直接的字符串匹配算法,它通过逐个字符比较来查找模式在文......
  • 算法面试准备 - 手撕系列第二期 - 交叉熵损失(Cross Entropy Loss)
    算法面试准备-手撕系列第二期-交叉熵损失(CrossEntropyLoss)目录算法面试准备-手撕系列第二期-交叉熵损失(CrossEntropyLoss)交叉熵原理图交叉熵损失实现代码-不同y_pre版本参考交叉熵原理图Softmax原理图交叉熵损失实现代码-不同y_pre版本......
  • 期望最大化算法:机器学习中的隐变量与参数估计的艺术
    引言在机器学习和统计学领域,许多实际问题涉及到含有隐变量的概率模型。例如,在图像识别中,图像的语义信息往往是隐变量,而我们能观测到的只是图像的像素值;在语音识别中,语音对应的文本内容是隐变量,观测数据则是语音信号。期望最大化(Expectation-Maximization,简称EM)算法作为一......
  • 通过一个算法的设计来了解栈的一些应用
    目录1.前言2.步骤3.代码实现4.测试5.运行结果6.一些思考7.一些应用示例1.前言掌握堆栈的基本原理掌握堆栈的存储结构掌握堆栈的进栈、出栈;判断栈空的实现方法掌握应用堆栈实现括号匹配的原理和实现方法;熟悉python语言编程熟练使用python语言实现堆栈的进栈Pus......
  • [需要复习的算法]算法目录
    1.十分基础1.算法1.枚举上链接!2.模拟上链接!3.分治上链接!4.贪心上链接!5.二分上链接!6.倍增上链接!7.排序上链接!比较基础的几种算法,多种算法依托在这几种思想上。要求:集合为一篇博客产出2.数据结构1.树 李老师的PDF2.图李老师的PDF3.栈 上链接!+李老师的PDF4......
  • 一个算法题目的探索
    首先提出一个简单的问题,之后在此基础上一步步进行拓展,整体上从易到难,逐渐深入。问题一给定\(n\)个区间\([l_i,r_i]\),选出至多\(2\)个两两不重叠的区间\([start_i,end_i]\),每个区间由\([l_x,r_y]\)组成(\(y\gex\)),最大化\(\sum(end_i-start_i)\)分析将\(n\)个区间......
  • 【优先算法】思还故里闾,欲归道无因 - 前缀和
    本篇博客给大家带来的是前缀和算法的知识点,也是一样通过OJ题理解,掌握,应用该算法.......