动画演示Sunday字符串匹配算法——比KMP算法快七倍!极易理解!
前言
上一篇我用动画的方式向大家详细说明了KMP算法(没看过的同学可以回去看看)。
这次我依旧采用动画的方式向大家介绍另一个你用一次就会爱上的字符串匹配算法:Sunday算法,希望能收获你的点赞关注收藏与转发哟!
KMP算法是一个里程碑似的算法,它的出现宣告了人类是找到线性时间复杂度的字符串匹配算法的。在这之后,出现了许多的字符串匹配算法,比如BM算法和Sunday算法。
这些算法在时间复杂度上都已经达到了线性时间。但是在实际应用的时候所耗费的时间却还是有所不同。
BM算法在实际应用中的效率已经达到了KMP算法的四五倍。
而Sunday算法的效率甚至犹在BM算法之上。
并且若是两种算法都了解的同学会明白:
Sunday算法比起BM算法来,真的极其容易理解。
正文
行,咱对Sunday算法的吹捧先到这为止,下面开始正戏!
PS:以下将带匹配字符串称为文本串,将用来匹配的字符串称为模式串。
为什么说Sunday算法极易理解呢?
因为它比暴力匹配算法只多了一个步骤而已!
话不多说,直接上我精心制作的GIF动态图:

可以看到,我们只移动了三次,就直接找到了最终的结果。
Sunday算法是从前往后匹配的算法(BM算法是从后向前的),在匹配失败时重点关注的是文本串中参加匹配的最末位字符的下一位字符。
如果该字符没有在模式串中出现则直接跳过,即移动位数 = 模式串长度 + 1。
否则,其移动位数 = 模式串长度 - 该字符最右出现的位置(以0开始) = 模式串中该字符最右出现的位置到尾部的距离 + 1。
Sunday算法最巧妙的地方,就在于它发现匹配失败之后可以直接考察文本串中参加匹配的最末尾字符的下一个字符。
在python代码中,我们利用字典来存储模式串中每个字符最后出现的索引,这样在前期只需O(M),M为模式串长度的时间即可做完前期准备,然后再进行查询都是O(1)的时间。
同时为了防止越界,我在下面贴出来的python代码中手动在字符串末尾加上了一个'\0'字符。
代码
class Sunday(object):
def __init__(self, pattern:str):
# 模式串和其长度
self.pattern, self.length = pattern, len(pattern)
# 根据模式串构建的偏移字典
self.shift_dict = {}
# 构建字典
for index, value in enumerate(pattern):
self.shift_dict[value] = self.length - index
def match(self, text:str):
i = 0
text_length = len(text)
text += '\0'
while i <= text_length - self.length:
j = 0
while self.pattern[j] == text[i + j]:
j += 1
if j >= self.length:
return i
offset = self.shift_dict[text[i+self.length]] if text[i+self.length] in self.shift_dict else self.length + 1
i += offset
return -1
s = Sunday('nihao')
print(s.match('dasoijfoasjdoifjasdoifjoinihao'))
代码十分的简单,同时,我构造了一个类,是为了在同一个模式串下能够复用它的位置字典,简化代码。
Sunday算法与KMP算法大比拼
在写完代码之后,我对KMP算法和Sunday算法的匹配时间进行了一个粗略的检测,检测结果如下:

amazing!,Sunday算法的平均匹配速度达到了KMP算法的七倍左右!
对KMP和Sunday各自构造了一个对象,然后每次生成一个随机的十万个字符长度的字符串让它们俩分别开始匹配。
生成-->匹配这个过程循环一百遍,最终计算平均时间。如果有大佬觉得不放心的,我在下方放出检测代码,大家可以自行修改测试,拿去即可用!
检测代码如下
class KMP():
def __init__(self, ss: str) -> list:
self.length = len(ss)
self.next_lst = [0 for _ in range(self.length)]
self.next_lst[0] = -1
i = 0
j = -1
while i < self.length - 1:
if j == -1 or ss[i] == ss[j]:
i += 1
j += 1
if ss[i] == ss[j]:
self.next_lst[i] = self.next_lst[j]
else:
self.next_lst[i] = j
else:
j = self.next_lst[j]
self.pattern = ss
def match(self, ss:str):
ans_lst = []
j = 0
for i in range(len(ss)):
if ss[i] != self.pattern[j]:
j = self.next_lst[j] if self.next_lst[j] != -1 else 0
if ss[i] == self.pattern[j]:
j += 1
if j == self.length:
return i + 1 - self.length
return -1
class Sunday(object):
def __init__(self, pattern:str):
# 模式串和其长度
self.pattern, self.length = pattern, len(pattern)
# 根据模式串构建的偏移字典
self.shift_dict = {}
# 构建字典
for index, value in enumerate(pattern):
self.shift_dict[value] = self.length - index
def match(self, text:str):
i = 0
text_length = len(text)
text += '\0'
while i <= text_length - self.length:
j = 0
while self.pattern[j] == text[i + j]:
j += 1
if j >= self.length:
return i
offset = self.shift_dict[text[i+self.length]] if text[i+self.length] in self.shift_dict else self.length + 1
i += offset
return -1
import random
import time
sunday = Sunday('helloworld')
kmp = KMP('helloworld')
kmp_average_time = 0
sunday_average_time = 0
for i in range(100):
ss = ''.join([chr(random.randint(97, 122)) for _ in range(100000)])
st = time.process_time()
sunday.match(ss)
ed = time.process_time()
sunday_average_time += ed - st
st = time.process_time()
kmp.match(ss)
ed = time.process_time()
kmp_average_time += ed - st
print('kmp平均时间: {}'.format(kmp_average_time / 100))
print('sunday平均时间: {}'.format(sunday_average_time / 100))
最后
最后,如果你觉得这篇文章对你有帮助的话呢,给我点个关注,收藏吧!
我的个人公众号是【程序小员】,欢迎你的关注,你的认可是我最大的动力!
我会持续更新对你有帮助的文章!
我是落阳,谢谢你的到访!
动画演示Sunday字符串匹配算法——比KMP算法快七倍!极易理解!的更多相关文章
- 字符串匹配算法之 kmp算法 (python版)
字符串匹配算法之 kmp算法 (python版) 1.什么是KMP算法 KMP是三位大牛:D.E.Knuth.J.H.MorriT和V.R.Pratt同时发现的.其中第一位就是<计算机程序设计艺 ...
- Python 细聊从暴力(BF)字符串匹配算法到 KMP 算法之间的精妙变化
1. 字符串匹配算法 所谓字符串匹配算法,简单地说就是在一个目标字符串中查找是否存在另一个模式字符串.如在字符串 "ABCDEFG" 中查找是否存在 "EF" ...
- 字符串匹配算法之————KMP算法
上一篇中讲到暴力法字符串匹配算法,但是暴力法明显存在这样一个问题:一次只移动一个字符.但实际上,针对不同的匹配情况,每次移动的间隔可以更大,没有必要每次只是移动一位: 关于KMP算法的描述,推荐一篇博 ...
- 字符串匹配算法之kmp算法
kmp算法是一种效率非常高的字符串匹配算法,是由Knuth,Morris,Pratt共同提出的模式匹配算法,所以简称KMP算法 算法思想 在一个字符串中查找另一个字符串时,会遇到如下图的情况 我们通常 ...
- 字符串匹配算法(三)-KMP算法
今天我们来聊一下字符串匹配算法里最著名的算法-KMP算法,KMP算法的全称是 Knuth Morris Pratt 算法,是根据三位作者(D.E.Knuth,J.H.Morris 和 V.R.Prat ...
- 数据结构学习之字符串匹配算法(BF||KMP)
数据结构学习之字符串匹配算法(BF||KMP) 0x1 实验目的 通过实验深入了解字符串常用的匹配算法(BF暴力匹配.KMP.优化KMP算法)思想. 0x2 实验要求 编写出BF暴力匹配.KM ...
- 字符串匹配算法之BM算法
BM算法,全称是Boyer-Moore算法,1977年,德克萨斯大学的Robert S. Boyer教授和J Strother Moore教授发明了一种新的字符串匹配算法. BM算法定义了两个规则: ...
- 数据结构4_java---顺序串,字符串匹配算法(BF算法,KMP算法)
1.顺序串 实现的操作有: 构造串 判断空串 返回串的长度 返回位序号为i的字符 将串的长度扩充为newCapacity 返回从begin到end-1的子串 在第i个字符之前插入字串str 删除子串 ...
- Sunday字符串匹配算法
逛ACM神犇的博客的时候看到的这个神奇的算法 KMP吧,失配函数难理解,代码量长 BF吧,慢,很慢,特别慢. BM吧,我不会写... 现在看到了Sunday算法呀,眼前一亮,神清气爽啊. 字符串匹配算 ...
随机推荐
- Blocks(POJ 3734)
原题如下: Blocks Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 8020 Accepted: 3905 Desc ...
- Django 页面之间传递MySql数据表(Django八)
之前实现了页面传递多个参数,但没有实现页面间传递一整个数据表 session传递几个参数:https://blog.csdn.net/qq_38175040/article/details/10496 ...
- docker导出导入镜像docker save和docker load的用法
1.百度搜的第一步是先将容器提交为镜像,然后用你提交的镜像去做上面的备份操作,提交为镜像后会新增一个镜像,但是感觉没有必要,直接做上面的save操作也是可以用的 百度的:docker commit 容 ...
- [Leetcode]148. 排序链表(归并排序)
题目 在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序. 示例 1: 输入: 4->2->1->3 输出: 1->2->3->4 示例 2: ...
- Charles介绍及配置
Charles 目录 Charles 1.先介绍一下Charles 2.缺少一点配置,需要配置一下 3.接下来就到安装证书了 重新打开一下,证书就安装成功了 这个是下载破解包的地址哦,可以选择版本 1 ...
- CentOS7使用PackageCloud安装RabbitMQ
环境:CentOS Linux release 7.6.1810 (Core) RabbitMQ:3.7.17Erlang: 22.0.7 使用PackageCloud安装RabbitMQ是最简单的安 ...
- Netty之ChannelOption的各种参数之EpollChannelOption.SO_REUSEPORT
socket选项 SO_REUSEPORT 转 miffa 发布于 2015/03/24 17:21 字数 3383 阅读 6076 收藏 6 点赞 1 评论 0 开发十年,就只剩下这套Java开发体 ...
- python3 函数的参数
函数的参数 形参(函数定义时) + 实参(函数调用时) 形参:形式参数 在函数的定义处定义的参数,比如def func(参数1, 参数2, 参数3...) 普通参数(位置参数), 默认参数,普通收集参 ...
- JDK动态代理学习心得
JDK动态代理是代理模式的一种实现方式,其只能代理接口.应用甚为广泛,比如我们的Spring的AOP底层就有涉及到JDK动态代理(此处后面可能会分享) 1.首先来说一下原生的JDK动态代理如何实现: ...
- python基本语法要注意哪些?本文详解!
基本语法 第一个注释 print("hello,python") # 第二行注释 string_demo = "你好!" string_demo print ( ...