Z Algorithm(扩展KMP)算法笔记

news/2025/2/19 15:25:35/

假设给定一个s长度为的n字符串。那么这个字符串的 z-function (“zet-function”)是一个长度为 的数组,其中的 -th 元素等于最大字符数,从 position i开始,i与字符串的第一个字符n重合。

换句话说,z[i]它是s字符串及其i-th 后缀的最大通用前缀。

注意:在本文中,为了避免歧义,我们将字符串视为0索引,即字符串的第一个字符具有索引0,最后一个n-1字符是。

z 函数的第一个元素通常z[0]被认为等于零。

本文描述了一种计算z函数的O (n)算法,以及该算法的各种应用。

例子

下面是针对多个计算的 z 函数的示例:

  • aaaaa
z[0] = 0,
z[1] = 4,
z[2] = 3,
z[3] = 2,
z[4] = 1
  • aaabaaab
z[0] = 0,
z[1] = 2,
z[2] = 1,
z[3] = 0,
z[4] = 2,
z[5] = 1,
z[6] = 0
  • abacbaa
z[0] = 0,
z[1] = 0,
z[2] = 1,
z[3] = 0,
z[4] = 3,
z[5] = 0,
z[6] = 1

朴素算法

以下算法基本实现时间复杂度O (n^2):

    public static int[] zFunction(String s){int n=s.length();char[]sa=s.toCharArray();int[] z=new int[n];for(int i=1;i<n;i++){while(i+z[i]<n&&sa[z[i]]==sa[i+z[i]]){++z[i];}}return z;}

对于每个位置i,我们只需从零开始迭代它的z[i]答案,直到我们发现不匹配或到达线的末尾。

计算 z 函数的有效算法

为了获得有效的算法,我们将逐个计算值,从i=1到,同时在计算下一个值时,我们将尝试n-1充分利用已经计算出的值z[i]。

为简洁起见s,我们将与字符串前缀匹配的子字符串称为匹配栏。例如,您要查找的z函数z[i]的值是从position开始(并将在positioni,i+z[i]-1结束)的最长匹配段。

为此,我们将保持重合最[左;r]右边段的坐标,即我们将存储在所有检测到的段的右侧结束的坐标。从某种意义上说,索引r是算法已经扫描了我们的字符串的边界,其他一切都还不知道。

然后,如果我们要计算z函数的下一个值的当前索引是i,我们有以下两个选项之一:

  • i>r—换句话说,目前的情况超出了我们已经处理的情况。
    然后我们将使用一个简单的算法进行搜索z[i],即只尝试、等的值z[i]=0。请注意,最后,如果z[i]结果是,z[i]=1那么我们将不得不更新最右边段[左;r]的坐标——因为它i+z[i]-1保证>0大r于。

  • i≤r—即当前位置位于重合段[左;r]内。
    在这种情况下,我们可以使用已经计算出的z函数的先前值来初始化值,而不是用零,而是用一些可能更高的数字来初始化值z[i]。

为此,请注意子字符串s[l…r]重合s[0…r-l]。这意味着作为初始近似值,z[i]我们可以从直线中获取相应的值,即s[0…r-l]值z[i-l]。

但是,该值z[i-l]可能太大,以至于当应用于某个位置我时,它会“爬出”边界r。这是不允许的,因为我们对右边的符号一无所知,而且它们可能与所需的符号r不同。

让我们举一个这种情况的例子,使用以下行作为示例:

aaaabaa

当我们到达最后一个位置i=6时,当前最右边的行是[5:6]。考虑到此段,该位置将对应6,6-5=1于答案等于z[1]=3的位置。显然,你不能用这样的值初始化z[6],这是完全不正确的。我们可以初始化的最大值是,因为它是1不超过[左;r]行的最大值。

因此,仅z[i]采用以下表达式作为初始近似值是安全的:

z_0[i]=min(r-i+1,z[i-l])。

使用z[i]这样的值初始化后,我们再次使用一个简单的算法,因为在边界之后,一般来说,可以找到z_0[i]线段的延续r,这是我们无法仅用z函数的先前值来预测的巧合。

因此,整个算法由两种情况组成,实际上仅在初始值上有所不同:在第一种情况下,假设它等于零,在第二种情况下,它由根据z[i]指定公式的先前值确定。之后,算法的两个分支都简化为执行一个从指定的初始值立即开始的简单算法。

事实证明,该算法非常简单。尽管他们每个人都我以一种或另一种方式执行一个微不足道的算法,但我们通过获得一种在线性时间内工作的算法取得了重大进展。为什么会这样,在我们介绍算法的实现之后,我们将在下面考虑。

实现

    public static int[] zFunction(String s){int n=s.length();char[]sa=s.toCharArray();int[] z=new int[n];int left=0,right=0;for(int i=1;i<n;i++){if (i<=right){z[i]=Math.min(right-i+1,z[i-left]);}while(i+z[i]<n&&sa[z[i]]==sa[i+z[i]]){++z[i];}if (i+z[i]-1>right){left=i;right=i+z[i]-1;}}return z;}

数组最初填充为z为0。假设当前最右边的重合部分等于[0;0],即一个故意的小部分,其中不会落i下

在循环中,我们首先使用上述算法来确定初始值z[i]——它要么保持为零,要么根据给定的i=1…n-1公式计算。

之后,执行一个简单的算法,试图尽可能地增加该值z[i]。

最后,如果需要[左;r]此更新,则更新匹配的当前最右边部分,即ifi+z[i]-1>r


http://www.ppmy.cn/news/1344150.html

相关文章

网易和腾讯面试题精选---API 设计和开发面试问答

介绍 API 设计和开发是不断发展的软件工程领域的关键组成部分。随着企业越来越依赖互连系统,创建强大、高效和用户友好的 API 的能力已成为科技行业抢手的技能。无论您是经验丰富的 API 开发人员还是准备面试的候选人,掌握 API 设计的复杂性都是至关重要的。本文深入探讨了一…

Node.js JSON Schema Ajv依赖库逐步介绍验证类型和中文错误提示

在构建应用程序时&#xff0c;数据的有效性是至关重要的。为了确保传入的数据符合预期的格式和规范&#xff0c;我们可以使用 Ajv&#xff08;Another JSON Schema Validator&#xff09;进行验证。在这篇博文中&#xff0c;我们将从头开始学习 Ajv&#xff0c;逐步介绍验证类型…

ChatGPT Plus如何升级?信用卡付款失败怎么办?如何使用信用卡升级 ChatGPT Plus?

ChatGPT Plus是OpenAI提供的一种高级服务&#xff0c;它相较于标准版本&#xff0c;提供了更快的响应速度、更强大的功能&#xff0c;并且用户可以优先体验到新推出的功能。 尽管许多用户愿意支付 20 美元的月费来订阅 GPT-4&#xff0c;但在实际支付过程中&#xff0c;特别是…

pytorch——保存‘类别名与类别数量’到权值文件中

前言 不知道大家有没有像我一样&#xff0c;每换一次不一样的模型&#xff0c;就要输入不同的num_classes和name_classes,反正我是很头疼诶&#xff0c;尤其是项目里面不止一个模型的时候&#xff0c;更新的时候看着就很头疼&#xff0c;然后就想着直接输入模型权值文件的path…

STM32学习笔记三——深度讲解GPIO及其应用

目录 STM32GPIO端口位基本结构图&#xff1a; 结构图I/O引脚&#xff1a; GPIO输入输出总结 1.GPIO引脚的四种输入方式及其特点&#xff1a; 1)上拉输入(GPIO_Mode_IPU) 2)下拉输入(GPIO_Mode_IPD) 3)模拟输入(GPIO_Mode_AIN) 4)浮空输入(GPIO_Mode_IN_FLOATING…

2024.2.5 寒假训练记录(19)

文章目录 牛客 寒假集训2A Tokitsukaze and Bracelet牛客 寒假集训2B Tokitsukaze and Cats牛客 寒假集训2D Tokitsukaze and Slash Draw牛客 寒假集训2E Tokitsukaze and Eliminate (easy)牛客 寒假集训2F Tokitsukaze and Eliminate (hard)牛客 寒假集训2I Tokitsukaze and S…

vue3学习——路由

安装 pnpm i vue-router/src/router/index.ts import { createRouter, createWebHashHistory } from vue-router import { constantRoute } from /router/routes.tslet router createRouter({history: createWebHashHistory(),routes: constantRoute, })export default rout…

【issue-YOLO】自定义数据集训练YOLO-v7 Segmentation

1. 拉取代码创建环境 执行nvidia-smi验证cuda环境是否可用&#xff1b;拉取官方代码&#xff1b; clone官方代码仓库 git clone https://github.com/WongKinYiu/yolov7&#xff1b;从main分支切换到u7分支 cd yolov7 && git checkout 44f30af0daccb1a3baecc5d80eae229…