zoukankan      html  css  js  c++  java
  • 子串周期查询问题的相关算法及其应用(原文为2019年国家集训队论文集)

    子串周期查询问题的相关算法及其应用

    南京外国语学校 陈孙立

    摘 要

    本文介绍了子串周期查询问题的解决方法, 以及解决这个问题所使用的到的一些结论和字符串工具——基本子串字典 (Dictionary of Basic Factors) , 接着介绍了前述结论和工具的一些应用.

    • 本文第二节引入了一些基础定义和记号.

    • 本文第三节证明了三个重要引理, 引入基本子串字典.

    • 本文第四节描述了解决子串周期查询问题的方法.

    • 本文第五节介绍了基本子串字典的一些应用.

    1 引言

    现阶段计算机科学界对字符串的研究越来越注重于对周期, 即" 重复模式" 的性质的探究. 这一方向也具有很大的现实意义, 如语音识别、DNA 匹配等, 它们都需要对大量重复的字符串模式的精巧刻画.

    子串周期查询问题是一个描述简单但是做法复杂的经典问题, 由此还可以延伸到应用更广的内部模式匹配 (Internal Pattern Matching) 问题. 本文着重介绍了它的解决办法, 以及一些扩展。

    2 记号、基础定义与问题描述

    2.1 记号与定义

    (S) 为一个字符串, (|S|)为其长度, 记 (S[i])(S) 的第 (i) 个字符, (S[l,r]) 为把 (S) 的第 (l) 个字符到第 (r) 个字符取出组成的新字符串, 若 (l>r)(S[l,r]=empty).

    (operatorname{pref}(S,x)=S[1dotsb x])(S) 的长度为 (x) 的前缀, 类似地, (operatorname{suf}(S,x)=S[|S|−x+1dotsb|S|])(S) 的长度为 (x) 的后缀.

    (T[xdotsb x+|S|−1]=S) , 我们说 (S)(T) 中的 (x) 位置出现, (x)(S)(T) 中的出现位置或匹配位置.

    定义 1: 若串 (S) 和整数 (x) 满足 (1leq xleq |S|) , 且对于所有的 (1leq ileq |S|−x) , 都有 (S[i]=S[i+x]) , 则称 (x) 为串 (S) 的周期或周期长度. 特别地, 若 (x) 还是 (|S|) 的因数, 则称 (x)(S) 的整周期, 称 (S) 是整周期串.

    显然, 若 (x)(S) 的周期, 则 (kx(kin ^+,kcdot|x|leq |S|)) 也是 (S) 的周期, (x) 也是 (operatorname{pref}(S,y),ygeq x) 的周期。

    定义 2: (operatorname{per}(S)) 表示所有 (S) 的周期组成的集合, (operatorname{minper}(S)) 表示 (operatorname{per}(S)) 中的最小值. 不难发现对于非空串 (S) , (|S|) 一定是 (S) 的周期, 因此 (|operatorname{per}(S)|>0).

    定义 3: 若串 (S) 和整数 (x) 满足 (0leq xleq |S|) , 且满足 (operatorname{pref}(S,x)=operatorname{suf}(S,x)) , 则称 (operatorname{pref}(S,x))(S)(mathrm{border}) .

    推论 1: (|S|−x)(S) 的周期当且仅当 (operatorname{pref}(S,x))(S)(mathrm{border}) .

    证明: 根据 (mathrm{border}) 和字符串相等的定义可得: (operatorname{pref}(S,x))(S)(mathrm{border}) 当且仅当对于所有的 (1leq ileq |operatorname{pref}(S,x)|) 都有 (operatorname{pref}(S,x)[i]=operatorname{suf}(S,x)[i]) , 也即 (S[i]=S[|S|−x+i]) , 与周期的定义相符.

    推论 2:(p)(S) 的周期, 且某个满足 (r−l+1geq p) 的子串 (S[ldotsb r]) 有周期 (q) , 并满足 (q|p) , 则 (q) 也是 (S) 的周期.

    此推论比较显然.

    2.2 问题描述

    给定一个字符串 (S) , 以及若干次询问. 每个询问给出 (l,r) 两个数, 要求给出 (operatorname{per}(S[ldotsb r])) .

    通过下文将要给出的结论, 可以用一种简洁的方式去表示 (operatorname{per}(S[ldotsb r])) , 花费 (O(log n))的空间, 而不是最坏情况下的 (O(|S|)) , 并且给出一个预处理需要 (O(nlog n)) 的时间与空间, 每次回答询问需要 (O(log n)) 的时间与空间的算法.

    3 解决问题的准备工作

    3.1 关于“重复”的一些性质

    关于字符串周期有一个重要的引理, 叫做 Periodicity Lemma. 它本身的证明比较繁琐, 下面我们证明它的弱化版本.

    引理 1 (Weak Periodicity Lemma) :(p,qinoperatorname{per}(S)) , 且 (p+qleq|S|) , 则 (gcd(p,q)in operatorname{per}(S)) .

    证明:不妨假设 (p<q) . 对于任意 (1leq ileq |S|) , 若 (p<ileq|S|−q+p) , 则 (S[i]=S[i−p]=S[i+q−p]) , 若 (i≤p) , 则 (S[i]=S[i+q]=S[i+q−p]) , 那么可得 (q−p) 也是 (|S|) 的周期. 这里用到了周期的定义和 (p+qleq|S|) 的条件. 而又有 (p+(q−p)leq|S|) , 所以可以用辗转相除法一直得到 (gcd(p,q))(|S|) 的周期.

    推论 3:(p=operatorname{minper}(S)leqfrac{|S|}{2}) , 则对于任意 (xin operatorname{per}(S),x+pleq |S|) , (有 p|x) .

    证明:若 (p mid x) , 根据 引理 1(gcd(p,x)in operatorname{per}(S)) , 而 (p<x) , 所以 (gcd(p,x)<p) , 与 (p=operatorname{minper}(S)) 矛盾.

    以下把 Weak Periodicity Lemma 简写为 WPL .

    引理 2 若串 (S,T) 满足 (2|S|geq|T|) , 则 (S)(T) 中的出现位置构成一个等差数列.

    证明:若 (S)(T) 中出现了一次或两次, 则引理已证完, 因此只需考虑 (S)(T) 中至少出现了 (3) 次.

    对于两次出现位置 (p<q) , 由于 (S)(T[pdotsb q+|S|−1])(mathrm{border}), 有 (q−p)(T[pdotsb q+|S|−1]) 的周期. 同时根据 (1leq p,qleq |T|−|S|+1) , 有 (p+|S|−1geq |S|geq |T|−|S|geq q) , 因此 (q−p<|S|) , 则 (q−p) 也是 (S) 的周期.

    那么我们考虑 (S)(T) 中的前两次出现位置 (p_1<p_2) 和某一次出现位置 (q>p2) , 有 (p_2−p_1,q−p_2in operatorname{per}(S)) . 又有 (q−p_1leq |T|−|S |leq |S|) , 根据 WPL 可得 (r=gcd(p_2−p_1,q−p_2)in operatorname{per}(S)) . 同时, 可以发现 (rleq min(p_2−p_1,q−p_2)leq frac{q−p_1}{2}leqfrac{|S|}{2}) . 令 (r'=operatorname{minper}(S)) , 那么根据 推论 3(r'|r) . 再根据 推论 2 , 得到 (r')(T[p_1dotsb p_2+|S|−1]) 的周期. 假设 (r'<r) , 根据前面的结论, (S)(p_1+r') 位置同样出现, 和 (p_2) 是第二次出现位置矛盾. 因此 (r=r'=operatorname{minper}(S)) .

    至此, 再使用一次 推论 3 , 就可以得到 (r|q−p_2) . 另一方面, 若令 (q)(S)(T) 中的最后一次匹配位置, 则任何满足 (x=p_1+krleq q,kin Z)(x) , 根据上面的结论, 都是 (S) 的出现位置. 综合这两个结论, 就证明了 引理 2 .

    不仅如此, 我们还得到了: 若 (S)(T) 中至少出现三次, 则对应等差数列的公差为 (operatorname{minper}(S)) .

    引理 2 示意图

    引理 3(S) 的所有不小于 (frac{|S|}{2})(mathrm{border}) 长度构成一个等差数列.

    证明:只需证明 (S) 的所有不大于 (frac{|S|}{2}) 的周期构成一个等差数列, 而这个结论可以由 推论 3 直接得到.

    3.2 数据结构:基本子串字典

    解决子串周期查询问题还需要一种被称为基本子串字典的数据结构。

    定义 4: 一个串 (S) 的基本子串字典 (Dictionary of Basic Factors) , 称为 (operatorname{DBF}(S)) , 它由 (lfloor log_2|S|⌋+1) 个数组组成. 具体地, 第 (t) 个数组用 (Name_t) 表示, 长度为 (|S|−2^t+1) , 满足 (Name_t(i)≤Name_t(j)) 当且仅当 (S[idotsb i+2^t−1]leq S[jdotsb j+2^t−1]) . 一般情况下, 可以再额外限制每个 (Name_t) 中的值为正整数, 且值域恰好为 ({1,2dotsb k}) , 其中 (kin ).

    不难发现, 数组 (Name_t) 可以由 (Name_t−1) 得到。因此要求出串 (S) 的基本子串字典, 直接使用类似 Manber & Myers 的倍增求后缀数组算法即可, 复杂度 (O(n log n)).

     的基本子串字典

    仅有 (Name) 数组可能还不够, 一个简单的扩展是把每个 (Name_t) 数组按值分开, 即对于每个 (x) 维护一个有序表, 记录 (Name_t[i]=x) 的所有的 (i) . 不难发现这一步也可以在构建基本子串字典的过程中完成, 复杂度依然是 (O(nlog n)) .

    后面将会看到, 为了达到目前最优的一次查询 (O(log n)) , 还要对基本子串字典的再次扩展.

    4 子串周期查询问题的解决

    4.1 基本算法

    定义 5: 对于两个串 (S,T) 满足 (|S|=|T|) , 定义 (operatorname{PS}(S,T)={k|operatorname{pref}(S,k)=operatorname{suf}(T,k)},operatorname{LargePS}(S,T)={k|kin operatorname{PS}(S,T),kgeqfrac{|S|}{2}}) .

    推论 4: (operatorname{LargePS}(S,T)) 的元素构成一个等差数列.

    证明:考虑其中最大的元素 (p) , 则对于任意 (qin operatorname{LargePS}(S,T)) , 有 (operatorname{pref}(S,q))(operatorname{pref}(S,p)) 的前缀, (operatorname{suf}(T,q))(operatorname{suf}(T,p)) 的后缀, 因此 (operatorname{pref(S,q)})(operatorname{pref}(S,p))(mathrm{border}) .
    根据 引理 3 , 其中的元素构成等差数列.

  • 相关阅读:
    MockMvc control层单元测试 参数传递问题
    @GetMapping和@PostMapping接收参数的格式
    获取 request 中用POST方式"Content-type"是"application/x-www-form-urlencoded;charset=utf-8"发送的 json 数据
    测试驱动开发实践—从testList开始
    深度解读
    深度解读
    3年不辭職!記住,在石頭上也要坐3年!(但也要区分5种不值得留的公司,12种留不住人才的公司)
    Configuring Your EMS Server or EMS Console Server on Windows/Linux
    XML 标准诞生 20 周年:这个世界,它无处不在
    通富微电石明达:成熟接班人也是先进生产力(执行力+判断力=抄底)
  • 原文地址:https://www.cnblogs.com/OIER-Yu/p/13364924.html
Copyright © 2011-2022 走看看