首页 > 其他分享 >Z 函数 / 扩展 KMP

Z 函数 / 扩展 KMP

时间:2023-10-11 14:33:51浏览次数:42  
标签:box 前缀 后缀 扩展 KMP 字符串 vert 函数

前置

  1. \(KMP\):\(O(n)\) 求解字符串匹配的算法。维护前缀数组 \(p_i\) 表示字符串 \(s\) 以 \(i\) 结尾的最长公共前后缀的长度;
  2. \(border\): 对于字符串 \(s\),如果存在一个子串 \(t\) 满足 \(t\) 既是 \(s\) 的一个前缀又是 \(s\) 的后缀,则称 \(t\) 是 \(s\) 的一个 border;

Z函数

定义:\(z_i\) 表示字符串 \(s\) 下标从 \(i\) 开始的后缀与 \(s\) 的最长公共前缀 (\(LCP\)) 的长度。这里我们规定字符串下标从 \(0\) 开始。

e.g.

​\(\ s: a\ a\ a\ a\ b\ a\ a\ b\)

​\(\ i:\ 0\ 1\ 2\ 3\ 4\ 5\ 6\ 7\)

​\(z_i: 8\ 3\ 2\ 1\ 0\ 2\ 1\ 0\)

注意,在处理不同的问题时 \(z_0\) 通常为 \(\vert s\vert\) 或 \(0\)。

对于字符串 \(s\) 的下标 \(i\),如果有 \(Z_i\neq 0\),那么称区间 \([i,i+z_i-1]\) 为一个 \(Z-box\)(匹配段)。

考虑如何实现求解Z函数。假定区间 \([l, r]\) 为找到的 \(Z-box\) 中 \(r\) 最靠右的哪一个匹配段,当前在考虑第 \(i\) 个位置。

  • 若 \(i>r\),则从下标 \(0\) 开始暴力匹配;
  • 若 \(i\le r\),
    • 若 \(i-z_{i-l} - 1 < r\),那么有 \(z_i=z_{i-l}\);
    • 若 \(i-z_{i-l}-1 \ge r\),暴力匹配

在每找到一个一个 \(Z-box\),更新 \(l=i,r=i+z_i-1\)。

单次暴力扩展至少使右端点 \(+1\),故暴力匹配的总时间是 \(O(n)\) 的。

对于 \(i-z_{i-l}-1 < r\) 的情况。由于 \([l,r]\) 是一个 \(Z-box\),所以 \(s[0,r-l]=s[l,r]\),同时因为 \(l\le i\le r\),有 \(s[i - l, r - l+1]=s[i,r]\)。这时候 \(z_i\) 就相当于是 \(z_{i-l}\),直接转移即可。

总时间复杂度 \(O(n)\)。

void Solve(string s) {
  z[0] = n = s.size();
  for(int i = 1, l = 0, r = 0; i < n; i++) {
    if(z[i - l] < r - i + 1) {
      z[i] = z[i - l];
    } else {
      for(z[i]= max(0, r - i + 1); i + z[i] < n && s[z[i]] == s[i + z[i]]; z[i]++) { // 暴力扩展
      }
      l = i, r = i + z[i] - 1;
    }
  }
}

应用

  1. 给定字符串 \(s,t\),求出 \(s\) 的每一个后缀与 \(t\) 的最长公共前缀。

    sol: 构造字符串 \(t+特殊字符+s\),然后求z函数即可。

  2. 求字符串 \(s\) 的所有 \(border\)。

    sol: 对于每一个位置 \(i\),如果有 \(i+z_i=\vert s\vert\),则当前以 \(i\) 开头的 \(Z-box\) 是一个 \(border\)。

  3. 求字符串 \(s\) 的每一个前缀的出现次数。

    sol: 对 \(z_i\) 的长度维护后缀和。因为对于位置 \(i\),若 \(z_i \ne 0\),则长度在 \([1,z_i]\) 内的前缀均出现了一次。

练习:

P5410 【模板】扩展 KMP/exKMP(Z 函数)

CF432D Prefixes and Suffixes

UVA11022 String Factoring

UVA11475 Extend to Palindrome

CF535D Tavas and Malekas

完结撒花 \ /\ / \ / \ /

标签:box,前缀,后缀,扩展,KMP,字符串,vert,函数
From: https://www.cnblogs.com/ereoth/p/17757014.html

相关文章

  • python:exec和eval函数使用
    我的案例方法:#函数公共配置defdebug_function(debug_req,function_text):try:exec(function_text)re=eval(debug_req)return{'code':200,'msg':'获取成功','data':re}exceptExceptionase:......
  • EM@三角函数诱导公式@三角函数式化简
    文章目录诱导公式锐角的三角函数是简单易求(易于表示)对于任意角之间,其各个三角函数之间存在某些关系需要讨论最基础最常用的三角函数诱导公式口诀同终边角在直角坐标系中,,的终边相同,则由三角函数定义,容易知道这两个的三角函数相等任意角的三角函数周内化根据同终边角三......
  • AM@映射@函数@反函数@复合函数
    文章目录abstract从两个角度定义函数及相关概念直接定义引入映射这一概念,然后借助映射来定义函数讨论函数的最基本内容讨论复合映射和复合函数讨论逆映射和反函数及其性质相关的符号表示含义解释直接定义函数的定义设两个变量,是一个非空的实数集若存在一个对应规则,使得对......
  • EM@对数@对数函数
    文章目录abstract从幂到对数的引入介绍对数相关性质公式对数函数及其性质幂指数和对数在指数函数中,对于实数集内的每一个指,正实数集内都有唯一确定的值和它对应;反之,对于正实数集内的每一个确定的值,在内部都有唯一确定的值和它对应**幂指数**又称为"以为底的对数",例如,那么......
  • SpringBoot的启动流程扩展点
    阅读说明:1.如果有排版格式问题,请移步https://www.yuque.com/mrhuang-ire4d/oufb8x/yo5ywqt5eudxvxfc?singleDoc#%20%E3%80%8ASpring%E5%8F%AF%E6%89%A9%E5%B1%95%E6%8E%A5%E5%8F%A3%E6%80%BB%E7%BB%93%E3%80%8B,选择宽屏模式效果更佳。2.本文为原创文章,转发请注明出处。SpringBoot......
  • 2023年10月10日 KdMapper扩展实现之SOKNO S.R.L(speedfan.sys)
    1.背景  KdMapper是一个利用intel的驱动漏洞可以无痕的加载未经签名的驱动,本文是利用其它漏洞(参考《【转载】利用签名驱动漏洞加载未签名驱动》)做相应的修改以实现类似功能。需要大家对KdMapper的代码有一定了解。 2.驱动信息 驱动名称speedfan.sys 时间戳50DF5......
  • php教程:变量、数据类型、运算符、数据结构、条件判断、循环、函数和面向对象
    变量<?php$x=5;$y=6;$z=$x+$y;echo$z;?>变量作用域全局变量在所有函数外部定义的变量,拥有全局作用域。要在一个函数中访问一个全局变量,需要使用global关键字。<?php$x=5;$y=10;functionmyTest(){global$x,$y;$y=$x+$y;}myTest();echo$y;//输出1......
  • 欧拉函数
    定义记欧拉函数\(\varphi(n)\)表示\(1\simn\)与\(n\)互质的整数的个数。性质若\(p\)为质数,则\(\varphi(p^k)=(p-1)\cdot\varphi(p^{k-1})\)。\(\varphi\)是积性函数。(积性函数\(f\):若\(a,b\)互质,则满足\(f(ab)=f(a)\cdotf(b)\))若\(n=\prod_{i=1}^mp_i^{\al......
  • Destoon Global 全局函数对应表
    函数名称https://www.clw9335.com/gl/index-htm-page-5.html作用参数dhtmlspecialchars($string)替换字符串中的&为&字符串daddslashes($string)字符转译字符串dstripslashes($string)字符反转译字符串dsafe($string)字符......
  • AbortController创建一个可中断的异步任务执行函数---【已解决】
    1、需求背景使用异步操作(promise)或者多个循环时,遇到不能及时中断操作,回收资源时2、代码/***创建一个可中断的异步任务执行函数。*@param{function}taskFunction-要执行的异步任务函数,接受一个AbortSignal参数用于中断。*@returns{object}包含执行任务和中断......