首页 > 编程语言 >day09 | KMP算法笔记

day09 | KMP算法笔记

时间:2024-06-22 11:32:17浏览次数:14  
标签:子串 day09 前缀 后缀 next int 算法 KMP charAt

目录

一、KMP算法有什么用?

二、构建next数组(就是前缀表)

1)什么是前缀表(next数组)

2)前缀表有什么用

3)前缀表怎么记录的?

4)为什么一定要用前缀表

5)构建next数组

三、力扣28.实现 strStr()

四、拓展题

重复的子字符串


一、KMP算法有什么用?

该算法主要应用在字符串匹配上,当模式串与文本串不匹配时,由于知道一部分已经匹配过的内容,可以避免从头再去匹配

如:文本串:aabaabaaf,模式串:aabaaf。

在匹配过程中'b'与'f'不匹配,暴力思想就是直接让模式串从文本串第二个'a'处重新匹配,时间复杂度O(m * n);而使用KMP算法,将会使模式串下标为2的'b'直接与文本串下标为5的'b'进行匹配,时间复杂度O(m + n)

二、构建next数组(就是前缀表)

1)什么是前缀表(next数组)

记录模式串下标i之前(包括i)的字符串中,有多大长度的相同前缀后缀

2)前缀表有什么用

用来回退的,它记录了模式串与主串(文本串)不匹配的时候,模式串应该从哪里开始重新匹配

3)前缀表怎么记录的?

计算模式串每一个子串最大相等前后缀,其中前缀是指不包含最后一个字符的所有以第一个字符开头的连续子串;后缀是指不包含第一个字符的所有以最后一个字符结尾的连续子串。

例如:模式串:aabaaf

子串a:无前后缀,最大相等前后缀长度为0

子串aa:前缀'a',后缀'a',最大相等前后缀'a',长度为1

子串aab:前缀'a','aa',后缀'b','ab',最大相等前后缀长度为0

子串aaba:前缀'a','aa','aab',后缀'a','ba','aba',最大相等前后缀'a',长度为1

子串aabaa:前缀'a','aa','aab'.'aaba',后缀'a','aa','baa','abaa',最大相等前后缀'aa',长度为2

子串aabaa:前缀'a','aa','aab'.'aaba'.'aabaa',后缀'af','aaf','baaf','abaaf',最大相等前后缀为0

0 1 0 1 2 0 就是模式串aabaaf的前缀表(也是我们需要构建的next数组)

4)为什么一定要用前缀表

例子:文本串:aabaabaaf,模式串:aabaaf。

下标5之前这部分的字符串(也就是字符串aabaa)的最长相等的前缀 和 后缀字符串是 子字符串aa ,因为找到了最长相等的前缀和后缀,匹配失败的位置是后缀'aa'的后面那么我们找到与其相同的前缀的后面重新匹配就可以了。

5)构建next数组

例子:模式串:aabaaf

指针i:1、用于标记待计算子串后缀末尾字符位置

2、[0,i]区间字符组成的就是待计算子串

指针j:1、表示的是当前待计算子串最大相等前缀的后一位(下次循环可以直接与i位置字符进行比较) 

2、也表示当前带计算子串最大相等前后缀的长度

(i = 1,待计算子串就是'aa',循环过后,j = 1,指向第二个'a',也就是'aa'最大相等前缀的后一位;同时,'aa'的最大相等前后缀的长度也是1)

(i = 4,待计算子串就是'aabaa',循环过后,j = 2,指向'b',也就是'aabaa'最大相等前缀的后一位;同时,'aabaa'的最大相等前后缀的长度也是2)

    public void getNext(int[] next, String s){
        int j = 0;
        next[0] = 0;
        for (int i = 1; i < s.length(); i++){
            while(j > 0 && s.charAt(i) != s.charAt(j)){ // j要保证大于0,因为下面有取j-1作为数组下标的操作
                j=next[j - 1]; // 注意这里,是要找前一位的对应的回退位置了
            }

            if(s.charAt(i) == s.charAt(j)){
                j++;
            }
            next[i] = j;//填充next数组
        }
    }

三、力扣28.实现 strStr()

题目链接:28. 找出字符串中第一个匹配项的下标

---给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回  -1 。

思路:KMP算法的基础题

class Solution {
    public int strStr(String haystack, String needle) {
        int[] next = getNext(needle);
        //这里采用for循环,必须先判断不相等,再判断相等的情况,不然循环结束进行i++操作,而j并没有进行加加操作,从而
        //导致当前j坐标的字符串又跟i++之后的字符进行匹配
        for(int i = 0,j = 0; i < haystack.length(); i++){
            while(j > 0 && needle.charAt(j) != haystack.charAt(i))
                j = next[j - 1];
            if(needle.charAt(j) == haystack.charAt(i)){
                j++;
                if(j == needle.length())return i + 1 - j;
            }
        }

        return -1;
    }
    //构建模式串的next数组
    public int[] getNext(String needle){
        //定义一个next数组
        int[] next = new int[needle.length()];
        int j = 0;
        next[0] = j;
        //采用for循环,必须先判断不相等,再判断相等,不然循环结束后进行i++操作,而j并没有加加,导致j更新不及时出错
        for(int i = 1; i < needle.length(); i++){
            while(j > 0 && needle.charAt(j) != needle.charAt(i)){
                j = next[j - 1];
            }
            if(needle.charAt(j) == needle.charAt(i))
                j++;
            next[i] = j;
        }

        return next;
    }
}

四、拓展题

重复的子字符串

题目链接:459. 重复的子字符串

---给定一个非空的字符串 s ,检查是否可以通过由它的一个子串重复多次构成。

思路:在由重复子串组成的字符串中,最长相等前后缀不包含的子串就是最小重复子串,这里拿字符串s:abababab 来举例,ab就是最小重复单位

正是因为 最长相等前后缀的规则,当一个字符串由重复子串组成的,最长相等前后缀不包含的子串就是最小重复子串。所以,我们只需判断该字符串长度 % 最长相等前后缀不包含的子串长度是否为0即可(先排除最大相等前后缀长度为0的情况),若为0,返回true;反之,返回false。

class Solution {
    public boolean repeatedSubstringPattern(String s) {
        int[] next = getNext(s);
        int lenS = s.length();
        if(next[lenS - 1] != 0  && lenS % (lenS - next[lenS - 1]) == 0){
            return true;
        }
        return false;
    }
    public int[] getNext(String s){
        int j = 0;
        int[] next = new int[s.length()];
        for(int i = 1; i < s.length(); i++){
            while(j > 0 && s.charAt(i) != s.charAt(j))
            j = next[j - 1];
            if(s.charAt(i) == s.charAt(j))
            j++;
            next[i] = j;
        }
        return next;
    }
}

标签:子串,day09,前缀,后缀,next,int,算法,KMP,charAt
From: https://blog.csdn.net/2301_76909842/article/details/139800180

相关文章

  • 【猫狗识别系统】图像识别Python+TensorFlow+卷积神经网络算法+人工智能深度学习
    猫狗识别系统。通过TensorFlow搭建MobileNetV2轻量级卷积神经算法网络模型,通过对猫狗的图片数据集进行训练,得到一个进度较高的H5格式的模型文件。然后使用Django框架搭建了一个Web网页端可视化操作界面。实现用户上传一张图片识别其名称。一、前言本研究中,我们开发了一个基于深......
  • 深度学习,强化学习,代码复现,文献复现,文章复现,科研复现,算法复现
    文章复现SCI代码复现文章代,文复现,具体包括:深度学习指导,计算机视觉辅导指导,目标检测图像分割,语义分割,算法性能提升,算法优化,模型修改,留学,人脸识别,文字识别口罩检测,人脸检测,车牌识别,GAN,yolo工业检测,异常检测,去噪,去模糊,异常检测,运动检测,VIT,点匹配,python指导,数据处理,医学影像分......
  • 【花雕学编程】Arduino FOC 之结合速度环的FOC算法
    Arduino是一个开放源码的电子原型平台,它可以让你用简单的硬件和软件来创建各种互动的项目。Arduino的核心是一个微控制器板,它可以通过一系列的引脚来连接各种传感器、执行器、显示器等外部设备。Arduino的编程是基于C/C++语言的,你可以使用ArduinoIDE(集成开发环境)来编写、......
  • 基于机会网络编码(COPE)的卫星网络路由算法matlab仿真
    1.程序功能描述       基于机会网络编码(COPE)的卫星网络路由算法。基于机会的网络编码(COPE,completelyopportunityencoding)方法,使每个接收节点都对信道进行侦听,通过获取邻居节点的信息状态确定编码机会,并且在本地信息缓存区中进行编码,最后进行基于编码机会的路由,可以有......
  • 代码随想录算法训练营第十四天 | 226.翻转二叉树 101.对称二叉树 104.二叉树的最大深
    226.翻转二叉树题目:给你一棵二叉树的根节点root,翻转这棵二叉树,并返回其根节点。解题:思路:遍历的过程中交换每个节点的左右孩子。选择哪种遍历方式?中序不行,左中右,左边子节点交换完,处理中间交换了左节点和右节点,再处理右节点去交换时这个右节点就是原来的左节点,所以有一边就一......
  • 【数据结构与算法 刷题系列】判断链表是否有环(图文详解)
                   ......
  • 对红酒数据集,分别采用决策树算法和随机森林算法进行分类。
    1.导入所需要的包fromsklearn.treeimportDecisionTreeClassifierfromsklearn.ensembleimportRandomForestClassifierfromsklearn.datasetsimportload_winefromsklearn.model_selectionimporttrain_test_split2.导入数据,并且对随机森林和决策数进行对比 x_tr......
  • 基于EKF算法估计电动汽车蓄电池的SOC
    电动汽车(EV)作为未来汽车的一大发展方向,其动力源——动力锂电池组的荷电状态(SOC)估计显得尤为重要。SOC直接反应了电池组剩余容量的多少,是预测EV行驶里程、使用和维护电池组的重要依据。然而,由于电动汽车电池组在使用过程中的高度非线性特性,准确估计SOC面临巨大挑战。扩展Kalman......
  • JavaScript算法之龟兔赛跑
    简介:龟兔赛跑算法,又称弗洛伊德循环检测算法,是一种在链表中非常常用的算法。它基于运动学和直觉的基本定律。本文旨在向您简要介绍该算法,并帮助您了解这个看似神奇的算法。假设高速公路上有两辆车。其中一辆的速度为x,另一辆的速度为2x。它们唯一能相遇的条件是它们都在循环......
  • K-means聚类是一种非常流行的聚类算法
    K-means聚类是一种非常流行的聚类算法,它的目标是将n个样本划分到k个簇中,使得每个样本属于与其最近的均值(即簇中心)对应的簇,从而使得簇内的方差最小化。K-means聚类算法简单、易于实现,并且在许多应用中都非常有效。K-means算法的基本步骤:选择初始中心:随机选择k个样本点作为初始......