• 经典算法:Z算法(z algorithm)

    • 1. 算法简介
    • 2. 算法原理
    • 3. 代码实现
    • 4. 推广应用
    • 5. 参考链接

1. 算法简介

Z algorithm是我今天做leetcode的时候偶然得知的一个用于字符串匹配的经典算法,我说怎么一个我几乎毫无解题思路的题目别人人均2分钟搞定,也是把我惊到了……

Anyway,能学到点东西倒也确实是个好事,至少以后知道这个套路了,LOL……

Z algorithm具体来说是用来求解字符串前序匹配的,具体而言,对于一个长度为n的输入字符串s,z algorithm返回一个长度为n的数组,其中对于每一个元素z[i],对应的含义就是子串s[i:]于s的最长公共前缀序列prefix的长度。

Leetcode第2223题(2223. Sum of Scores of Built Strings)就是上述算法的一个典型应用。

实现这个功能,最为直接的方法就是一个二次循环进行匹配,不过这样的话显然算法复杂度是非常高的,但是Z algorithm的巧妙之处就在于其可以在O(N)O(N)O(N)的算法复杂度范围内对上述功能进行实现。

2. 算法原理

z算法的核心算法原理就是尽可能地重用之前已经匹配过的结果。

具体实现而言,我们维护一个滑动窗口[L,R][L, R][L,R],这个滑动窗口表示当前最接近的且已经匹配过的与开头的前缀字符串最长的匹配字符。即:

  • S[L:R+1] == S[:R-L+1]
  • S[L:R+2] != S[:R-L+2]

然后,我们来考察每一个位置i上面的z[i]的值:

  1. 如果i>R,那么我们之前从来没有匹配过从第i个位置开始的字符串,那么,我们将L更新为i,然后逐一对R进行考察,找到最长的子串S[L:R+1]使得S[L:R+1] == S[:R-L+1],此时z[i] = R-L+1;
  2. 如果i<=R,那么我们一定在之前已经在窗口中见过了S[i],一定有S[i] == S[i-L],定义k=i-L,那么我们同样可以进行分类讨论:
    1. 如果z[k] < R-i+1,那么i+z[k] <= R,说明S[i:i+z[k]+1]同样已经之前在窗口中已经匹配过了,是从S[k]开始匹配的最长的前缀子串,即S[i:i+z[k]+1] == S[k:k+z[k]+1] == S[:z[k]+1],因此我们可以直接复用之前的结果,即z[i] = z[k],而滑动窗口无需进行变动;
    2. 如果z[k] >= R-i+1,那么i+z[k] > R,说明S[i:R+1] == S[k:k+R-i+1] == S[:R-i+1],那么我们可以更新滑动窗口的左侧边界L=i,然后继续对右侧窗口进行匹配,直到找到新的右侧窗口匹配边界R'

综上,我们即可得到除了第一个字符之外的所有的位置上的z[i]的值,而对于第一个位置上的z[0],显然这个值就是字符串的长度n

由此,全命题解毕。

另外,关于上述算法的算法复杂度,由于这里的滑动窗口的有边界R的移动是单向的,因此,整体的算法复杂度一定是O(N)O(N)O(N)的。

3. 代码实现

我们根据上述原理分析就可以快速地给出一个Z algorithm的python代码实现如下:

def z_algorithm(s):n = len(s)z = [0 for _ in range(n)]l, r = -1, -1for i in range(1, n):if i > r:l, r = i, iwhile r < n and s[r-l] == s[r]:r += 1z[i] = r-lr -= 1else:k = i - lif z[k] < r - i + 1:z[i] = z[k]else:l = iwhile r < n and s[r-l] == s[r]:r += 1z[i] = r-lr -= 1z[0] = nreturn z

4. 推广应用

z algorithm的另一个常见的应用就是用于字符串匹配。

典型的问题就是:

给出一个待匹配字符串s和一个模式字符串pattern,问字符串s当中是否存在pattern以及存在多少pattern的个数。

最trivial的方法同样可以使用一个二重循环,不过算法复杂度就是O(nm)O(nm)O(nm)。

不过,借用Z algorithm的思路,我们可以将其算法复杂度压缩到O(n+m)O(n+m)O(n+m),具体来说,我们只需要将pattern拼接到待匹配字符串s之前,然后求一下z算法之后移除掉前方的pattern,然后看一下剩下的z值当中是否有长度不小于m的存在即可。

给出python代码实现如下:

def have_pattern(s, pattern):t = pattern + sz = z_algorithm(t)z = z[len(pattern):]return any(x >= len(pattern) for x in z)

5. 参考链接

  1. https://www.geeksforgeeks.org/z-algorithm-linear-time-pattern-searching-algorithm/
  2. https://www.hackerearth.com/practice/algorithms/string-algorithm/z-algorithm/tutorial/

经典算法:Z算法(z algorithm)相关推荐

  1. Python:实现字符串Z 函数或 Z 算法(附完整源码)

    Python:实现字符串Z 函数或 Z 算法 def z_function(input_str: str) -> list[int]:z_result = [0 for i in range(l ...

  2. Java算法题:Z字形变换

    Java算法题:Z字形变换 将一个给定字符串 s 根据给定的行数 numRows ,以从上往下.从左到右进行 Z 字形排列. 比如输入字符串为 "PAYPALISHIRING" 行 ...

  3. 算法导论 13.3 RB-INSERT-FIXUP(T, z)算法中的缩进问题

    感觉好像是少了一个换行符... 修正后是这样: RB-INSERT-FIXUP(T, z) 1 while z.p.color == RED 2 if z.p == z.p.p.left 3 y = ...

  4. 经典常用算法/常用算法思维---附伪代码以及实现

    本篇文章旨在分享一些常用算法的伪代码以及部分算法的具体实现,后面也会更新我在刷算法题中学到的或者从别的地方看到的经典算法思维 本博客并不提供算法说明,算法证明,算法分析,算法测试等内容,只提供算法的伪 ...

  5. 【机器学习入门】图解超经典的KNN算法

    出品:Python数据之道(ID:PyDataLab) 作者:Peter,来自读者投稿 编辑:Lemon 图解超经典的KNN算法 本文中介绍的机器学习算法中的一种监督学习的算法:KNN 算法,全称是 ...

  6. 【转载】(EM算法)The EM Algorithm

    (EM算法)The EM Algorithm EM是我一直想深入学习的算法之一,第一次听说是在NLP课中的HMM那一节,为了解决HMM的参数估计问题,使用了EM算法.在之后的MT中的词对齐中也用到了. ...

  7. 汇集YOLO系列经典和前沿算法,实现高精度实时检测!

    YOLO(You Only Look Once,你只看一次)是一阶段目标检测算法的开山之作.常年来,YOLO系列模型统治着实时目标检测界,其代名词就是"快".从2016年Josep ...

  8. 机器学习算法系列(五)- Lasso回归算法(Lasso Regression Algorithm)

    阅读本文需要的背景知识点:线性回归算法.一丢丢编程知识 最近笔者做了一个基于人工智能实现音乐转谱和人声分离功能的在线应用--反谱(Serocs),感兴趣的读者欢迎试用与分享,感谢您的支持!serocs ...

  9. CEC2017:斑马优化算法(Zebra Optimization Algorithm,ZOA)求解cec2017(提供MATLAB代码)

    一.斑马优化算法 斑马优化算法(Zebra Optimization Algorithm,ZOA)Eva Trojovská等人于2022年提出,其模拟斑马的觅食和对捕食者攻击的防御行为. 斑马因身上 ...

最新文章

  1. 如果地府需要一个后台管理系统,你会如何设计?
  2. cmyk图像处理matlab,数字图像处理及MATLAB实现 全套课件.pptx
  3. OpenGL Assimp模型加载库
  4. Java技术栈---语言基础
  5. python3虚拟环境使用教程_python虚拟环境完美部署教程
  6. Python 本身真的有用吗?CSDN要对Python下手了!
  7. 《大型网站技术架构》1.大型网站架构演练
  8. Java内存优化和性能优化的几点建议
  9. ap_invoice_distributions_all到xla_ae_lines
  10. [转载] Python time sleep()方法如何使用?
  11. Atitit 调用百度语音识别 目录 1. 建立一个音频app项目,获得appid kersec 1 2. 直接使用JAR包步骤如下: 1 2.1. public class baiduAudio
  12. c语言课程设计万年历查询,C语言课程设计——万年历.pdf
  13. 怎样使用思维导图做计划?分享5个思维导图做计划的模板
  14. Hbase 过滤器详解
  15. 机器视觉(4)-- 云台人脸追踪
  16. java绘图- 绘图用法(基于Graphics2D)
  17. 数据分析_表和表的运用
  18. vue通过URL传递参数
  19. Cannot resolve table ‘r_resume‘ Inspection info: This inspection controls whether the Persistence
  20. 旅游出境登机入住饭店英语

热门文章

  1. 理解高斯混合模型中期望最大化的M-Step
  2. js手机格式校验+隐藏手机号中间四位,变成*星号 || 身份证生日四位变*,邮箱*号显示
  3. bert第三篇:tokenizer
  4. huggingface Tokenizers 官网文档学习:tokenizer训练保存与使用
  5. 深入理解JavaScript执行上下文与作用域链
  6. android 插件化 方案,Android应用开发之Android 插件化,qihoo360插件方案配置教程
  7. 服务器创建和附加虚拟磁盘,详解Hyper-V创建虚拟磁盘存储配置攻略
  8. 柑橘黄龙病微生物组研究
  9. MyBatis(十四)MyBatis的缓存
  10. JS实现简易版备忘录