【KMP算法】时间复杂度O(N)的字符串匹配算法

news2024/11/23 9:07:14

目录

案例:假定我们给出字符串 ”ababcabcdabcde”作为主串, 然后给出子串: ”abcd”,现在我们需要查找子串是否在主串中 出现,出现返回主串中的第一个匹配的下标,失败返回-1 ;

1.BF算法(暴力算法)

2.KMP算法

1.next数组

 2.代码中如何实现next数组;

 3.代码实现

4.next数组优化


案例:假定我们给出字符串 ”ababcabcdabcde”作为主串, 然后给出子串: ”abcd”,现在我们需要查找子串是否在主串中 出现,出现返回主串中的第一个匹配的下标,失败返回-1 ;

1.BF算法(暴力算法)

思路:遍历主串,子串和当前位置的比较;匹配成功返回主串当前位置,主串遍历完成都没有匹配成功,返回-1;

代码:

#include<iostream>
#include<string>
using namespace std;

int BF(string str,string sub)
{
    int strlen=str.size();
    int sublen=sub.size();
    //遍历主串,和子串比较
    for(int i=0;i<strlen-sublen+1;i++)
    {
        int t=i,j=0;
        for(;j<sublen;j++)
        {
            if(str[t++]!=sub[j])
                break;
        }
        if(j==sublen)
            return i;
    }
    return -1;
}
int main()
{
    cout<<BF("ababcabcdabcde","abcd")<<endl;
    return 0;
}

结果:

时间复杂度:O(N^2) (或者O(strlen*sublen))  空间复杂度:O(1)

2.KMP算法

概念:KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是通过一个next()函数(数组)实现,函数本身包含了模式串的局部匹配信息。KMP算法的时间复杂度O(m+n) [1] (看不懂看下面的例子)

思想:在子串和主串不匹配,两者前面的元素一定相同

  • 如果主串当前位置前n个和子串的前n个相同,让子串以O(1)时间复杂度返回到相同部分的下一个位置

结合子串和主串前面元素相同,实际找子串的前n项和后n项也是一样效果

1.next数组

next数组:next【0】设置为-1,是否能在当前位置前面找到两个以第一个元素开始,(当前位置-1)元素结束的字符串,如果找得到当前位置的next【i】为第一个字符串最后一个元素(子串下标是-1的,next[i]==2, 子串实际是第3个元素);找不到next【i】=0(子串下标-1,实际是第一个元素);

 

 2.代码中如何实现next数组;

  1. next【0】=-1,next【1】=0(前面只有一个元素);
  2. 当前位置i,如果前一个位置,子串【i-1】等于子串【next【i-1】】,当前位置next【i】=next[i-1]+1;
  3. 子串【i-1】不等于子串【next【i-1】】,重复这个过程,一直没有等于最后会到第一个元素,next【第一个元素】值为-1,当前位置next【i】=-1+1;

 3.代码实现

  • KMP算法在字符串匹配中的时间复杂度:O(N)   空间复杂度:O(N)
#include<iostream>
#include<string>
#include<vector>
using namespace std;

void BuildNextFunc(vector<int> &next,string &sub,int len)
{
    next[0]=-1;
    if(len>1)
    {
        next[1]=0;
        for(int i=2;i<len;i++)
        {
            //前一个等于特点位置
            if(sub[i-1]==sub[next[i-1]])
            {
                next[i]=next[i-1]+1;
            }
            else
            {
                int t=next[i-1];
                while(next[t]!=-1&&sub[i-1]!=sub[t])
                {
                    t=next[t];
                }
                next[i]=next[t]+1;
            }
        }
    }
}
int KMP(string str,string sub)
{
    if(str.empty()||sub.empty())
        return -1;
    int strlen=str.size();
    int sublen=sub.size();
    int subi=0,stri=0;
    vector<int> next(sublen);
    BuildNextFunc(next,sub,sublen);
    while(subi<sublen&&stri<strlen)
    {
        //相同继续比较下一个,回退到-1说明子串当前第一个元素就和主串不同,所以++
        if(subi==-1||str[stri]==sub[subi]){
            subi++;
            stri++;
        }
        //不相同,回退到特点位置,可能回退到-1
        else{
            subi=next[subi];
        }
    }
    if(subi==sublen)
        return stri-subi;
    return -1;    
}
int main()
{
    cout<<KMP("ababcabcdabcde","abcd")<<endl;
    cout<<KMP("ababcabcdabcde","")<<endl;
    cout<<KMP("ababcabe","abcd")<<endl;
    return 0;
}

4.next数组优化

next 数组的优化,即如何得到 nextval 数组:有如下串: aaaaaaaab,他的 next 数组是-1,0,1,2,3,4,5,6,7. 而修正后的数组 nextval 是-1, -1, -1, -1, -1, -1, -1, -1, 7;

伪代码:sub[i]==sub[  next[i]  ],nextval[i]=nextval[  next[i]  ]

为什么可行:KMP算法就是如果不相同子串到next【i】去,然后继续比较,当前位置是i,变到next【i】,i位置就是因为值和主串的值不同才到next【i】位置的,现在i和next【i】的值相同,还得比较后继续next【i】到next【next【i】】

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/685665.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java8新特性之--强大的Stream API详细讲解

强大的Stream API Stream API说明 Java8中有两大最为重要的改变。第一个是 Lambda 表达式&#xff1b;另外一个则 是 Stream API。Stream API ( java.util.stream) 把真正的函数式编程风格引入到Java中。 这是目前为止对Java类库最好的补充&#xff0c;因为Stream API可以极…

CVPR 23 | 高分辨率缺陷异常定位新范式:PyramidFlow

来源&#xff1a;投稿 作者&#xff1a;橡皮 编辑&#xff1a;学姐 论文链接&#xff1a;https://arxiv.org/abs/2303.02595 论文代码&#xff1a;暂未发布 0. 背景 由于复杂的工业制造过程中的不可控因素&#xff0c;不可避免地会给产品带来不可预见的缺陷。由于人类视觉系…

使用亮数据Bright Data解决出境电商问题

目录 一、出境电商的困境和问题1、困境一&#xff1a;获取准确的市场数据&#xff08;1&#xff09;数据的时效性和可靠性&#xff08;2&#xff09;数据的全面性和多样性&#xff08;3&#xff09;数据的实时更新和持续监测 2、困境二&#xff1a;克服地域限制和语言障碍&…

scratch数星星 2023年5月中国电子学会图形化编程 少儿编程 scratch编程等级考试三级真题和答案解析

目录 scratch数星星 一、题目要求 1、准备工作 2、功能实现 二、案例分析

基于Java学生信息管理系统设计实现(源码+lw+部署文档+讲解等)

博主介绍&#xff1a; ✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战 ✌ &#x1f345; 文末获取源码联系 &#x1f345; &#x1f447;&#x1f3fb; 精…

vue中js实现点击复制文本到剪贴板-三种方案

vue中js实现点击复制文本到剪贴板-三种方案 因为在网上找了一些很杂乱 不适用 所以自己写一篇记录分享一下 vue中js实现点击复制文本到剪贴板-三种方案 效果&#xff1a; 方案一&#xff1a;使用原生API&#xff08;clipboard&#xff09; 首先&#xff0c;我们需要安装clip…

【嵌入式5】电源相关芯片驱动

文章目录 1.读MPS5023芯片&#xff1a;0x03ff即将前6位屏蔽2.读PXE1410CDM电压和电流&#xff1a;一个数&0x7ff&#xff0c;将这个数前5位全变为0&#xff0c;其余位不变2.1 1ine11&#xff1a;先看第15和10位&#xff0c;e9b6是上面读出的值2.2 1ine16&#xff1a;PMBUS协…

产品的0到1概念篇

一、产品是什么&#xff1f; 产品是指被人们使用和消费&#xff0c;并能满足人们某种需求的任何东西&#xff0c;包括有形的物品、无形的服务、组织、观念或它们的组合。 产品本质是什么&#xff0c;产品的本质就是解决⽤户的痛点/满⾜⽤户的需求&#xff0c;这种满⾜的需求&…

KingbaseES的学习心得和知识总结(二)|Kingbase数据库闪回功能及插件kdb_flashback的使用

目录结构 注&#xff1a;提前言明 本文借鉴了以下博主、书籍或网站的内容&#xff0c;其列表如下&#xff1a; 1、KingbaseES V8产品文档首页&#xff0c;点击前往 2、Kingbase 文档库&#xff0c;点击前往 3、北京人大金仓信息技术股份有限公司 官网首页&#xff0c;点击前往…

详解服务器端渲染 页面(SSR)

&#x1f48c;目录 &#x1f525;先了解服务器端渲染 (SSR)&#xff1f;&#x1f525;服务器端渲染的优点是什么呢&#xff1f;&#x1f525;有优点就有缺点&#xff1f;&#x1f525;根据Express来简单的建立一个服务端渲染 &#x1f525;先了解服务器端渲染 (SSR)&#xff1f…

Qt6.2教程——7.QT常用控件QTextEdit

一&#xff0c;QTextEdit简介 QTextEdit 是 Qt 的一个用于编辑和显示纯文本和富文本的控件。它是功能强大且高度灵活的&#xff0c;可以用于实现多种任务&#xff0c;如文本编辑&#xff0c;数据表示&#xff0c;以及HTML的显示和编辑等。QTextEdit 支持富文本功能&#xff0c…

Over 函数的使用

序言 其实也很少使用这个Over函数,毕竟mysql在5.7版本之前都是不支持的,但是over()的窗口概念被Flink中的窗口中借鉴了. 所以了解下,网上的Over()的使用有在Mysql中的例子,但是我的Mysql5.7 不支持,所以在Oracle中实验.但是语法都是一样的.cuiyaonan2000163.com 众所周知如果S…

转战VUE3学习

安装好vue3后&#xff0c;开始新的项目吧&#xff01; npm init vuelatest1.组合式API 在以前vue2的项目里&#xff0c;使用的选项式API将各种不同逻辑的代码分散到像data、methods等不同的对象里。如果想看某一方面的逻辑&#xff0c;鼠标滚轮都要磨出火星了&#xff01; 而…

LLM的工程实践思考

陆奇博士的主题演讲《新范式 新时代 新机会》非常震撼人心。我远程参加了深圳站和北京站两场演讲&#xff0c;深受感触。虽然了解大模型的机制和原理以了解新的范式非常重要&#xff0c;但是“行胜于言”&#xff0c;基于大模型的众多应用都需要工程技术才能落地。然而&#xf…

Ndk c++层 crash问题分析

首先你要从设备上拿到墓碑文件&#xff1a;tombstone&#xff0c;这里面会记录系统崩溃时的信息。位置在/data/tombstones目录下&#xff08;Logcat中也会有相应的信息&#xff09;&#xff0c;文件的确就像墓碑一样记录了死亡了的进程的基本信息&#xff08;例如进程的进程号&…

FlashAttention和PagedAttention

FlashAttention FlashAttention一般指的是FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness这篇&#xff0c;当然Transformer Quality in Linear Time这篇里非要说FLASH Fast Linear Attention with a Single Head&#xff0c;命名有点无语&…

JavaScript数据存储方式

内置对象 js内部提供的对象&#xff0c;包含各种属性和方法给开发者调用 document.write() console.log() Math Math对象是js提供的一个 “数学”对象&#xff0c;提供了一系列做数学运算的方法 max找最大值Math.max(3,8,5,4) 返回8min找最小值Math.min(3,8,5,4) 返回4ab…

printf不一样的玩法

Printf不一样的玩法 ❝ 在使用linux终端命令的时候&#xff0c;我们可以看到像more命令&#xff0c;它的显示方式与一般的字符串不同&#xff0c;是用了反显。同样&#xff0c;linux C下printf还有很多其他不常见的格式化输出形式。本文主要为你盘点这些形式。 ❞ 先看下效果&a…

MySQL:单行函数(全面详解)

MySQL&#xff1a;单行函数 前言一、函数的理解1、什么是函数2、不同DBMS函数的差异3、MySQL的内置函数及分类 二、数值函数1、基本函数2、角度与弧度互换函数3、三角函数4、指数与对数5、进制间的转换 三、字符串函数四、日期和时间函数1、获取日期、时间2、日期与时间戳的转换…

Bpmn.js流程建模结合业务整合工作流(二)

上一篇文章讲述了bpmn.js的基本搭建使用过程,下面介绍工具栏的按钮使用 以及右侧属性如何绑定到节点保存的 保存方法 /** 保存xml */async save() {await this.getNewXML() //获取最新的xmlawait this.getRootElement() //获取流程基本信息 节点信息const params = {name: th…