首页 > 编程语言 >28:KMP算法

28:KMP算法

时间:2024-08-20 13:51:08浏览次数:13  
标签:cn int str2 28 length next ++ 算法 KMP

KMP算法的用途是:在一个字符串中找到某一个字串的位置。

时间复杂度是O(N)

代码:

package algorithmbasic.basicsets.class28;

public class KMP {
    public static int getIndexOf(String s1, String s2) {
        if (s1 == null || s2 == null || s1.length() < 1 || s2.length() < 1 || s2.length() > s1.length()) {
            return -1;
        }
        char[] str1 = s1.toCharArray();
        char[] str2 = s2.toCharArray();

        int[] next = makeNextArray(str2);

        int x = 0;
        int y = 0;

        while (x < str1.length && y < str2.length) {
            /**
             * 跳出循环分三种情况
             * 1:当 x == str1.length && y != str2.length ==> 没有在str1中找到str2.
             * 2:当 x == str1.length && y == str2.length ==> 在最后的时候正好找到了。.
             * 3:当 x != str1.length && y == str2.length ==> 在前面就找到了.
             */
            if (str1[x] == str2[y]) {
                x++;
                y++;
            } else if (next[y] == -1) { // y == 0 , 说明x所在的位置没有一个跟他匹配成功的,那就x++,继续向下找吧。
                x++;
            } else {
                y = next[y]; // 直接来到next[y]位置与x位置进行比较。
            }
        }
        return y == str2.length ? x - y : -1;
    }

    private static int[] makeNextArray(char[] str2) {
        if (str2.length < 2) {
            return new int[]{-1};
        }
        int[] next = new int[str2.length];
        next[0] = -1;
        next[1] = 0;
        int i = 2;
        int cn = 0;
        while (i < str2.length) {
            if (str2[cn] == str2[i - 1]) {
                next[i++] = ++cn;
            } else if (cn > 0) { // 说明i-1位置是有最大相同字串的
                cn = next[cn];
            } else { // cn退到最开始的位置都不相等。说明当前i位置压根没有最大相同字串。
                next[i++] = 0;
            }
        }
        return next;
    }
}

next数组:

在这里插入图片描述

next数组里面记录的是什么,next数组里面记录的是当前位置(i)之前(不包括当前位置)最大的相同子串的长度(对两个子串的要求是:第一个子串以0下标开始,第二个子串以当前位置的前一个位置(i - 1)结尾,并且子串的长度不可以等于当前位置之前的整个串的长度([0 , i-1]))

next数组的规定:第一个-1,第二个是0.

分析一下整个KMP算法的算法流程:

开始的时候,i指针与j指针一一对应的分别遍历str1与str2,当不一样的时候,拿到 j 位置所对应的next数组的值z,也就是A部分 == B == C,j 位置直接指向 z(因为A == B ,B== C 所以 A == C,所以前部分不需要比对,因为一定相等) ,然后继续往后比对 i 位置与 j 位置的值循环往复。特殊的情况是:当 j 指向0位置的时候,还没有比对上,那就让 i++ 继续比对下一个位置,说明没有一个是合适的。

跳过的中间的部分没有一个是合适的所以就直接舍弃了,直接跳到B部分进行比对。

假设中间的一部分有等于str2的,那么

在这里插入图片描述

创建next数组的流程

在这里插入图片描述

当前来到i位置,i位置之前的最大相同子串的长度就是A == B,然后 i++,来到当前的 i 位置,现在我只需要判断

str2[ j ] 是否等于 str2[ i - 1 ] 即可。如果这两个位置相同,那么就让A,B吞进去就可以了。

在这里插入图片描述

如果这两个位置不同,就寻找 j 位置之前的最大相同字串 C ,D 。A中的C,D分别映射着B中的C’ , D‘,(C == D == C’ == D’ )。然后 j 指向 next[ j ] 位置。判断此时 str2[ j ] 是否等于 str2[ i - 1] .如果等于的话C , D’吞进去接可以了。

时间复杂度分析:

创建next数组的时间复杂度分析

	private static int[] makeNextArray(char[] str2) {
     if (str2.length < 2) {
         return new int[]{-1};
     }
     int[] next = new int[str2.length];
     next[0] = -1;
     next[1] = 0;
     int i = 2;
     int cn = 0;
     while (i < str2.length) {
         if (str2[cn] == str2[i - 1]) {
             next[i++] = ++cn;
         } else if (cn > 0) { // 说明i-1位置是有最大相同字串的
             cn = next[cn];
         } else { // cn退到最开始的位置都不相等。说明当前i位置压根没有最大相同字串。
             next[i++] = 0;
         }
     }
     return next;
 }

i 是没有回退的,是一步一步线性向前的。 cn是有回退的增长。所以分析时间复杂度的时候单独分析cn不好分析。

在这里插入图片描述

kmp算法时间复杂度分析

public static int getIndexOf(String s1, String s2) {
     if (s1 == null || s2 == null || s1.length() < 1 || s2.length() < 1 || s2.length() > s1.length()) {
         return -1;
     }
     char[] str1 = s1.toCharArray();
     char[] str2 = s2.toCharArray();

     int[] next = makeNextArray(str2);

     int x = 0;
     int y = 0;

     while (x < str1.length && y < str2.length) {
         /**
             * 跳出循环分三种情况
             * 1:当 x == str1.length && y != str2.length ==> 没有在str1中找到str2.
             * 2:当 x == str1.length && y == str2.length ==> 在最后的时候正好找到了。.
             * 3:当 x != str1.length && y == str2.length ==> 在前面就找到了.
             */
            if (str1[x] == str2[y]) {
                x++;
                y++;
            } else if (next[y] == -1) { // y == 0 , 说明x所在的位置没有一个跟他匹配成功的,那就x++,继续向下找吧。
                x++;
            } else {
                y = next[y]; // 直接来到next[y]位置与x位置进行比较。
            }
        }
        return y == str2.length ? x - y : -1;
    }

x 是没有回退的,是一步一步线性向前的。 y是有回退的增长。所以分析时间复杂度的时候单独分析y不好分析。

跟上面是同样的分析方法。

标签:cn,int,str2,28,length,next,++,算法,KMP
From: https://blog.csdn.net/SCR1209/article/details/141338264

相关文章

  • Java实现冒泡排序和插入排序算法
    冒泡排序算法步骤1、比较相邻的元素,如果第一个比第二个大,就交换它们两个;2、对每一对相邻元素作同样的比价,从开始第一对到结尾的最后一对,这样在最后的元素就是最大的数;3、针对所有的元素重复以上的步骤,除了数组最后已经排好序的数组;4、重复步骤1~3,直到排序完成。代码实现pac......
  • 「代码随想录算法训练营」第四十二天 | 单调栈 part2
    42.接雨水题目链接:https://leetcode.cn/problems/trapping-rain-water/文章讲解:https://programmercarl.com/0042.接雨水.html题目难度:困难视频讲解:https://www.bilibili.com/video/BV1uD4y1u75P/题目状态:这道题目在LeetCodeTop100中做过,使用两种方法,再回顾一下思路一:单......
  • 大模型算法必学,万字长文Llama-1到Llama-3详细拆解
    导读Llama系列的大语言模型在多个自然语言处理任务中表现出色,包括文本分类、情感分析和生成式问答,本质是使用Transformer架构并结合预训练和微调技术。本文详细讲解Llama-1到Llama-3,值得读者点赞收藏!引言在AI领域,大模型的发展正以前所未有的速度推进技术的边界。北京......
  • Oracle RAC 集群启动顺序 转发:https://www.modb.pro/db/1824295923545612288?utm_s
    前言前几天使用脚本在RockyLinux9.4安装Oracle11GR2RAC,安装完之后发现集群无法正常启动,后经过分析发现原来是因为RHEL9版本默认安装移除了 initscripts 软件包,需要人为手动安装,在RHEL8之前是默认安装的。在分析问题的过程中,顺便对OracleRAC集群启动顺序进行了更......
  • 基于Hadoop的异构网络协同过滤推荐算法设计
    基于Hadoop的异构网络协同过滤推荐算法设计DesignofHeterogeneousNetworkCollaborativeFilteringRecommendationAlgorithmbasedonHadoop完整下载链接:基于Hadoop的异构网络协同过滤推荐算法设计文章目录基于Hadoop的异构网络协同过滤推荐算法设计摘要第一章......
  • 数据结构day01(数据结构、算法基础知识)
    目录【1】数据结构基础知识1》什么是数据结构2》数据 3》逻辑结构1>线性关系2>层次关系3>网状关系4》存储结构  1>顺序存储 2>链式存储3>索引存储结构 4>散列存储 5》操作【2】算法基础知识1>什么是算法 2>算法设计 3>算法的特性 4>评价算法的......
  • 【图像处理】在图像处理算法开发中,有哪些常见的主观评价指标和客观评价指标?
    主观评价指标        在图像处理算法开发中,主观评价指标依赖于观察者的个人感受和判断,通常用于评估图像的视觉质量。以下是一些常见的主观评价指标:平均意见分数(MeanOpinionScore,MOS):通过收集多个评价者的评分并计算平均值来评估图像质量。差异平均意见分数......
  • 实战教程:Python实现高校爬虫,运用协同过滤与k-means算法进行专业评分分析
    ......
  • Java常见算法
    Java作为一种广泛使用的编程语言,支持实现多种算法。这些算法可以根据其用途、复杂度、数据结构和应用领域进行分类。以下是一些Java中常见的算法示例:排序算法:冒泡排序:通过重复地遍历要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。遍历数列的工作是重复......
  • 【数据结构与算法第一章】编程基础:变量与数据类型、指针、结构体、数组与链表、程序结
    目录【数据结构与算法第一章】编程基础1.1变量与数据类型1.2指针1.3结构体1.4数组和链表1.5程序结构1.6函数中参数的传递1.7C语言中运算符的含义【数据结构与算法第一章】编程基础1.1变量与数据类型变量:    ①在C语言中,所有变量必须先声明后使用......