KMP模式匹配算法(一)从暴力匹配切入

副业刚需
• 阅读 2461

最近在看关于算法方面的,正好看到关于KMP算法相关的部分,这里就做一个总结。
假设我们有这样的一个主串

S = 'googlgomglegoogle'

和一个子串

C = 'google'

我们现在有这样的一个需求那就是要在主串S中找到子串C出现的位置。可能马上会有很聪明的同学提出来,可以用indexOf方法啊。那我只能说这个方法不算。。。

朴素的模式匹配算法

这种算法又被称为暴力匹配算法。
也就是逐位匹配,假设主串的位置i子串的位置j,如果有位置j和位置i的字符相等的话,i++, j++。如果匹配失败,则回溯到主串的下一个位置重新逐位匹配。好的,我知道你肯定没有听明白,还是直接上代码好了。

var S = 'googlgomglegoogle'
var C = 'google'

var sPositon = 0
function violence1() {
  for (var i in C) {
    if (C.charAt(i) !== S.charAt(sPositon)) {
      sPositon += 1
      violence1()
    }
  }
  console.log(sPositon)
}

violence1()

然后就悲剧了

for (var i in C) {
           ^

RangeError: Maximum call stack size exceeded

超过最大调用堆栈大小, 递归没有终止会永远的循环下去,内存已爆。所以递归套循环还是需要谨慎。
好吧,那这样我们就改变一下。下面我写了两种实现方式

// 暴力匹配1
for (let i = 0; i < mainStr.length; i += 1) {
  for (let j = 0; j < searchStr.length; j += 1) {
    if (searchStr[j] !== mainStr[i + j]) {
      break
    } else if (searchStr[searchStr.length - 1] === mainStr[i + j]) {
      console.log(i)
    }
  }
}

// 暴力匹配2

let i = 0
let j = 0
while (i < mainStr.length && j < searchStr.length) {
  if (mainStr[i] === searchStr[j]) {
    i += 1
    j += 1
  } else {
    i += 1
    j = 0
  }
}
if (j === searchStr.length) {
  console.log(i - j)
} else {
  console.log('-1')
}

输出结果是11,还是很符合我们预期的效果的。那现在我们来分析一下这个算法的复杂度怎么样。
当然,在匹配算法中不同的输入会有不同的复杂度,最好的情况就是一开始就匹配成功。比如

S = 'googlestwo'
C = 'google'

此时的时间复杂度是O(1)
稍微差一点的情况,就是前几位的每一位都和子串的第一位不匹配,例如

S = 'abcderfgoogle'
C = 'google'

此时的时间复杂度为O(m + n), m为主串的长度,n为子串的长度。
最后我们分析最极端也就是最坏的情况也就是每一次不成功的匹配都发生在子串的最后一位,例如

S = 'googlgooglgooglgooglgooglgooglgooglgooglgooglgooglgooglgoogle'
C = 'google'

你说这气人不气人,就像炸金花的时候前两张都是红桃,最后一张突然蹦出个梅花,而且每把都这样。。。
此时的时间复杂度为O((n-m+1)m)
很显然这样的运行效率是十分低的。所以我们需要更加高效的算法-KMP模式匹配算法。
切入结束,下篇详解KMP匹配算法

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Karen110 Karen110
3年前
一篇文章带你了解JavaScript日期
日期对象允许您使用日期(年、月、日、小时、分钟、秒和毫秒)。一、JavaScript的日期格式一个JavaScript日期可以写为一个字符串:ThuFeb02201909:59:51GMT0800(中国标准时间)或者是一个数字:1486000791164写数字的日期,指定的毫秒数自1970年1月1日00:00:00到现在。1\.显示日期使用
待兔 待兔
11个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
一些常见的字符串匹配算法
字符串匹配在文本处理的广泛领域中是一个非常重要的主题。字符串匹配包括在文本中找到一个,或者更一般地说,所有字符串(通常来讲称其为模式)的出现。本文为大家介绍一些常见的字符串匹配算法
红橙Darren 红橙Darren
3年前
Android模板设计模式之 - 构建整个应用的BaseActivity
1\.模式介绍模式的定义定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。所有分享大纲:视频讲解地址:模式的使用场景1.多个子类有公有的方法,并且逻辑基本相同时。2.重要、复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由各个子类实现。3.重构时,模板方法模式
Karen110 Karen110
3年前
​一篇文章总结一下Python库中关于时间的常见操作
前言本次来总结一下关于Python时间的相关操作,有一个有趣的问题。如果你的业务用不到时间相关的操作,你的业务基本上会一直用不到。但是如果你的业务一旦用到了时间操作,你就会发现,淦,到处都是时间操作。。。所以思来想去,还是总结一下吧,本次会采用类型注解方式。time包importtime时间戳从1970年1月1日00:00:00标准时区诞生到现在
Stella981 Stella981
3年前
OpenJDK11与Spring Cloud Finchley的不兼容问题与解决
本文的环境:OpenJDK11.0.4,SpringCloudfinchleySR4,SpringBoot2.0.3最近遇到了一个问题,在feign调用的时候,时常会出现这样一个奇怪的错误:2019100708:00:00.620ERRORxxx,e1ba4c7540954aa3,871b99c4576d42e3
Stella981 Stella981
3年前
AC(Aho—Corasiek) 多模式匹配算法
简介:AC多模式匹配算法产生于1975年的贝尔实验室,最早使用于图书馆的书目查询程序中。该算法以有限状态自动机(FSA),以及KMP前缀算法为基础.(有说法:ac自动机是KMP的多串形式,是一个有限自动机)AC定义:AC有限自动机M是1个6元组:M(Q,∑,g,f,qo,F)其中:1、Q是有
搜索中常见数据结构与算法探究(二)
本文介绍了几个常见的匹配算法,通过算法过程和算法分析介绍了各个算法的优缺点和使用场景,并为后续的搜索文章做个铺垫;读者可以通过比较几种算法的差异,进一步了解匹配算法演进过程以及解决问题的场景;KMP算法和DoubleArrayTireTree是其中
分布式系统的主键生成方案对比 | 京东云技术团队
UUID​UUID(通用唯一识别码)是由32个十六进制数组成的无序字符串,通过一定的算法计算出来。为了保证其唯一性,UUID规范定义了包括网卡MAC地址、时间戳、名字空间(Namespace)、随机或伪随机数、时序等元素,以及从这些元素生成UUID的算法。
美凌格栋栋酱 美凌格栋栋酱
5个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(