Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >KMP 算法

KMP 算法

作者头像
MashiroT
发布于 2023-03-14 09:53:42
发布于 2023-03-14 09:53:42
26900
代码可运行
举报
文章被收录于专栏:MashiroのBlogMashiroのBlog
运行总次数:0
代码可运行

KMP 算法

简介

Knuth-Morris-Pratt字符串查找算法(简称为KMP算法)可在一个字符串S内查找一个词W的出现位置。一个词在不匹配时本身就包含足够的信息来确定下一个匹配可能的开始位置,此算法利用这一特性以避免重新检查先前配对的字符。——引自维基 在模式匹配问题中,KMP算法比Manacher算法更具普适性,Manacher算法只适用于 回文串 问题,较为局限。

例题引入

LeetCode 28. 找出字符串中第一个匹配项的下标 为例 题目给出一个字符串 text 和一个模式串 pattern,要求返回 text 中第一次匹配模式串的下标 例:text = ababc, pattern = abc, answer = 2

暴力解法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static int strStr(String text, String pattern) {
    int textLen = text.length();
    int patternLen = pattern.length();
    for (int i = 0; i < textLen - patternLen; i++) {
        boolean flag = true;
        for (int j = 0; j < patternLen; j++) {
            if (pattern.charAt(j) != text.charAt(i + j)) {
                flag = false;
                break;
            }
        }
        if (flag) {
            return i;
        }
    }
    return -1;
}

很容易看出时间复杂度为 O(m * n)

原因是每次内循环匹配失败后,j 总是回溯到0,重新匹配 而匹配失败的意思是当前字符不匹配,而当前字符之前的子串是匹配的 而KMP算法就是利用了这一特性,使得复杂度降低到了 O(m + n)

KMP算法

最长公共前后缀

前缀是指不包含最后一个字符的所有以第一个字符开头的连续子串 后缀是指不包含第一个字符的所有以最后一个字符结尾的连续子串 例如: aabaa 的前缀是 aaba 后缀是 abaa公共 则要求前后缀相等 则 aabaa 的最长公共前后缀是 aa

next数组

我们用 i 表示字符串的结尾,j 表示该字符串前缀的结尾

> 构造next数组的过程其实是 pattern**自我匹配** 的过程

pattern = aabaaf

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
"a" 无意义,不满足前后缀定义,i 从 1 开始
"aa"     i = 1, j = 1, next[1] = 1
"aab"    i = 2, j = 0, next[2] = 0
"aaba"   i = 3, j = 1, next[3] = 1
"aabaa"  i = 4, j = 2, next[4] = 2
"aabaaf" i = 5, j = 0, next[5] = 0

代码实现

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int patternLen = pattern.length();
    int[] next = new int[patternLen];
//    构造next[]
//    i 指向 子串的最后
//    j 指向 前缀的最后
    for (int i = 1, j = 0; i < patternLen; i++) {
//        不匹配, j 为 长度-1 子串的结果
        while (j > 0 && pattern.charAt(i) != pattern.charAt(j)) {
            j = next[j - 1];
        }
        if (pattern.charAt(i) == pattern.charAt(j)) {
            j++;
        }
//        长度为 i 的子串的最长公共前后缀的长度为 j, 索引为 j - 1
//        即存放公共前后缀之后的字符的索引
        next[i] = j;
    }
匹配搜索
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int textLen = text.length();
//    search
//    i 指向 text
//    j 指向 pattern
    for (int i = 0, j = 0; i < textLen; i++) {
//        不匹配, j 为 长度-1 子串的结果,
//        直到匹配, 边界情况为 j = 0
        while (j > 0 && text.charAt(i) != pattern.charAt(j)) {
            j = next[j - 1];
        }
//        匹配, j 后移
//        除前面全不匹配外,均匹配
        if (text.charAt(i) == pattern.charAt(j)) {
            j++;
        }
        if (j == patternLen) {
            return i - patternLen + 1;
        }
    }
实现
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static int kmp(String text, String pattern) {
        int textLen = text.length();
        int patternLen = pattern.length();
        int[] next = new int[patternLen];
//        构造next[]
//        i 指向 子串的最后
//        j 指向 前缀的最后
        for (int i = 1, j = 0; i < patternLen; i++) {
//            不匹配, j 为 长度-1 子串的结果
            while (j > 0 && pattern.charAt(i) != pattern.charAt(j)) {
                j = next[j - 1];
            }
            if (pattern.charAt(i) == pattern.charAt(j)) {
                j++;
            }
//            长度为 i 的子串的最长公共前后缀的长度为 j, 索引为 j - 1
//            即存放公共前后缀之后的字符的索引
            next[i] = j;
        }
//        search
//        i 指向 text
//        j 指向 pattern
        for (int i = 0, j = 0; i < textLen; i++) {
//            不匹配, j 为 长度-1 子串的结果,
//            直到匹配, 边界情况为 j = 0
            while (j > 0 && text.charAt(i) != pattern.charAt(j)) {
                j = next[j - 1];
            }
//            匹配, j 后移
//            除前面全不匹配外,均匹配
            if (text.charAt(i) == pattern.charAt(j)) {
                j++;
            }
            if (j == patternLen) {
                return i - patternLen + 1;
            }
        }
        return -1;
    }

</br></br> 参考资料: 1.KMP 算法详解 2.代码随想录 3.【喵的算法课】KMP算法 av808837277 4.【宫水三叶】简单题学 KMP 算法 5.海纳的知乎回答 6.Wiki

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023 年 02 月,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Manacher 算法
> 马拉车算法 Manacher‘s Algorithm 是用来查找一个字符串的最长回文子串的线性方法,由一个叫Manacher的人在1975年发明的,这个方法的最大贡献是在于将时间复杂度提升到了线性。
MashiroT
2023/03/14
2260
Manacher 算法
LeetCode647. 回文子串
给你一个字符串 s ,请你统计并返回这个字符串中 回文子串 的数目。 回文字符串 是正着读和倒过来读一样的字符串。 子字符串 是字符串中的由连续字符组成的一个序列。 具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。
MashiroT
2023/03/14
1610
[NetWork] 华为设备常用命令配置
题记 该命令由本人收集记录摘抄,如需原件请联系我 /* ############################# &#x57FA;&#x7840;&#x547D;&#x4EE4;&#x7BC7; ############################# */ system-view /*&#x8FDB;&#x5165;&#x7CFB;&#x7EDF;&#x89C6;&#x56FE;*/ sysname [name] /*&#x4FEE;&#x6539;&#x8BBE;&#x5907;&#x540D;&
BreezeCloud
2022/12/04
2140
CentOS 7搭建OpenV**
PS:目前openvpn服务器已经搭建完成了,但是有个问题,只要有上述三个证书文件和服务器IP信息,任何人都可以连接服务器,为了安全考虑,我们可以采取用户认证的方式管理,详情见:OpenVPN使用用户密码认证登录
孤鸿
2022/10/04
5150
思科 H3C | Vlan间路由
Vlan间路由 > 定义: 指对设备不同的vlan间进行三层数据转发 > 实现方式: 使用三层交换机实现[现在主流]: H3C三层交换机实现vlan互通 #&#x9996;&#x5148;&#x8FD8;&#x662F;&#x5728;&#x4EA4;&#x6362;&#x673A;&#x5185;&#x521B;&#x5EFA;vlan vlan [ID] #&#x518D;&#x6765;&#x662F;&#x5728;&#x4E09;&#x5C42;&#x4EA4;&#x6362;&#x673A;&
BreezeCloud
2022/10/04
2130
[NetWork] ACL访问控制列表
访问控制列表:ACL+Packet-filter 用ACL搭配包过滤 路由控制:ACL+Route-policy 用ACL将要匹配的数据提取出来,在配合路由策略在实现其他功能 流量控制:ACL+QOS 用ACL将要匹配的数据提取出来,配置QOS策略做相关的操作
BreezeCloud
2022/11/18
9890
[NetWork] ACL访问控制列表
[NetWork] EPON基本概述
PON(Passive Optical NetWork-基于物理层的协议)又叫无源光网 他的架构是基于点到多点(P2MP) 交换机的角色被替换成了POS、分光器 其中分光器不需要电源
BreezeCloud
2022/11/22
1.2K0
[NetWork] EPON基本概述
vscode-go 远程开发添加golangci-lint支持
vscode对远程开发的支持可谓一骑绝尘。关于golangci-lint的支持方法,网上已经很多。但没有找到远程开发的配置,故摸索了一番。
超级大猪
2024/05/21
2980
vscode-go 远程开发添加golangci-lint支持
BAT文件加密解密
> 因为工作的原因不希望bat脚本内容让其他人知道,于是找到了加密bat文件的方法,防止别人随意修改,下面整理一下bat脚本加密解密的方法!
孤鸿
2022/10/04
5.1K0
[NetWork] IPSec VPN
IPsec > IP Security 是一种网络层的安全保障机制或者说是体系 通过各种机制和协议实现安全保障 IPsec可以实现: <code>1. 访问控制</code> <code>2. 机密性</code> <code>3. 完整性</code> <code>4. 数据源验证</code> <code>5. 拒绝重播报文</code> 等安全功能 他可以引入多种验证算法、加密算法和秘钥管理机制 IPSec VPN是利用IPsec 隧道实现的L3 VPN IPSec也具有配置复杂,消耗运算资源较多、增加延时、不支持组播等缺点
BreezeCloud
2022/12/04
7.3K0
[NetWork] IPSec VPN
CentOS7安装NextCloud
为了您服务的安全和性能, 请将所有设置配置正确. 我们将会进行一些自动化检查以帮助您完成这项工作. 详情请查看 "小提示" 部分及相关文档.
孤鸿
2022/10/04
6620
Centos7搭建CiscoAnyConnect
配置环境 yum -y install epel-release #&#x5B89;&#x88C5;EPEL&#x6E90; yum install ocserv #&#x5B89;&#x88C5;ocserv 配置OpenConnectServer 准备证书 创建证书目录 cd ~ mkdir certificates cd certificates 在此目录下创建一个名为 ca.tmpl 的CA证书模板,写入如下语句: cn = &quot;Aierpf&quot; organization =
孤鸿
2022/10/04
9670
LeetCode 312.戳气球
有 n 个气球,编号为0 到 n - 1,每个气球上都标有一个数字,这些数字存在数组 nums 中。
MashiroT
2023/03/14
3580
[NetWork] 以太网接入
AGG:Aggregation 汇聚设备 AN:Access Node 接入设备 HG:Home GateWay 家庭网关
BreezeCloud
2022/11/22
5050
[NetWork] 以太网接入
DIY激光雕刻机-超牛逼的电子制作 开启DIY创作之旅
这里要注意一下,并不是所有的材料都可以雕刻的,一般选用深色的东西比较好,也就是要吸光的东西,木板是最好的材料,但是我这边没有我就用快递盒的纸片(俗称牛皮纸),其次我发现生活中常用的卡片也是可以的,比如银行卡,只要卡片上有一层喷绘就可以,
幻影网络
2022/11/08
9250
DIY激光雕刻机-超牛逼的电子制作 开启DIY创作之旅
[NetWork] 路由过滤
RIP协议中,静默接口不发送路由更新 OSPF协议中,静默接口不发送Hello报文 大多数配置静默接口的场景是业务网段不希望收到协议报文的时候
BreezeCloud
2022/11/18
1.1K0
[NetWork] 路由过滤
OpenV**使用用户名密码验证
> 如果无法下载就把下面的内容拷贝到一个文件中,然后改名为checkpw.sh即可
孤鸿
2022/10/04
1.3K0
Spring OAuth 简单实践
最近在了解OAuth2.0,一直想搞一个自己的类似于SakuraFrp使用的OpenID授权站,就想自己写一个。找的很多国内教程用的包都是 spring-cloud 下的关于 oauth 的包,或是直接使用老版本的 security-oauth 包,由于 spring-security 最新版是 6.x ,教程的版本太老,且想使用 start.spring.io 中提供的 spring-boot-starter-oauth2-xxx 使用配置文件快速开发,写下本文记录。
MashiroT
2023/10/18
2490
Spring OAuth 简单实践
Vlan的概念以及配置
如果MAC地址绑定到VLAN,同一MAC地址的设备,无论在哪个接口 他所属的VLAN都不会变化 端口需要配置为Hybrid
BreezeCloud
2023/01/08
8700
Vlan的概念以及配置
博客搭建(三):域名配置及SSL证书配置
> 现在大多数网站都支持 https 连接,而且 chrome 浏览器要求网站必须提供 https 连接,否则会提示警告(此网站不安全),所以说以后网站支持 https 连接是必不可少的。
子晋
2022/01/18
8650
相关推荐
Manacher 算法
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档