荒芜卡纸协调(wildcard matching)

荒芜卡纸协调(wildcard matching)

它给我们一个这样的承诺,一切可能发生的事情总会发生.

也就是通配符匹配啦,这个标题是方便检索的.

关于什么是通配符

通配符是一种特殊符号,用来代替一个或多个字符进行模糊匹配。当你记不清完整名字,或者想批量操作一批文件时,就会用到它。(by AI)

关于一些记号和约定

\(S_k\) 字符串的第 \(k\) 个字符, 0-index.

\(S_{[l,r)}\) 字符串的第 \(l\) 个字符到第 \(r\) 个字符组成的子串, 左闭右开.

\(\Sigma\) 字符集

先来给出匹配的一般定义, 给定文本串 \(T\) 和模式串 \(P\)

称其匹配当且仅当 \(length(T)=length(P)\)\(\forall i\in [0,len(T)),T_i=P_i\)

在大部分匹配问题里, 文本串是给定的, 不含通配符.

单字符通配

对单字符通配来说, 某个由 (各种) 通配符组成的字符串可以视作由一系列字符集的子集组成的序列 \(S\)(通配符不视作字符集的一部分), \(S_k\subset \Sigma\), 此时, 字符串匹配即

\(length(T)=length(P)\)\(\forall i\in [0,len(T)), T_i\cap P_i\neq \emptyset\)

例如, 普通的字符在这个形式下就是由它自己组成的集合, 可以匹配任何字符的 \(\text{?}\) 对应的集合就是字符集本身.

例如, 这两个字符串之间是匹配的.

\(\text{Text?}\)

\(\text{Text1}\)

对于大部分场景, 计算两个对应集合是否有交一般可以做到 \(O(1)\) , 即使集合显式给出, 总可以做到 \(O(|\Sigma|)\), 而此时的输入规模已经是 \(O(n|\Sigma|)\) 因此计算两个含单字符通配符的字符串是否匹配是平凡的.

因此我们来考察一个实用的问题, 给定文本串 \(T\) 和模式串 \(P\) 找到 \(P\)\(T\) 中所有能够匹配的子串, 由于长度固定, 自然, 在单字符通配匹配中这个问题就等价于找到所有能够匹配的子串的起始点.

我们可以在如下的几个场景下考察此问题, 在此基础又要考虑文本串含不含通配符.

(1). 仅考虑 \(\text{?}\)

(2). 考虑常数种通配符, 比如 \(\text{[a-z]},\text{[0-9]}\) (匹配小写字母和数字)

(3). 完全给出匹配的子集

(2)和(3)之间还存在一类关于通配符的种类数的帕累托最优问题.

这里主要考察 (1), 不过会顺带几句.

BF algorithm

我们记 \(|T|=n,|P|=m\), (1)(2)容易做到 \(O(nm)\) .

对于 (3), 容易做到 \(O(nm\frac{|\Sigma|}{w})\)

fft

考虑一个有趣的想法, 先不考虑通配符, 我们可以通过向量内积来计算两个字符串是否匹配.

大家可以先想想有什么构造方法呢?

这里介绍几个方法, 还有更多,. 不过请读者自行思考.

最直观的方法自然是我们希望找到一个多项式函数, 两个字符匹配为 \(0\), 不匹配是正数, 那么累加后只要判断是否是 \(0\) 即可.

考虑 \(|a-b|\), 但这不是关于 \(a,b\) 的多项式, 不便于点积计算, 这并不难解决, 平方即可.

那么我们就得到了一个可用的匹配函数 \((a-b)^2\) .

实际上, 任何在两个参数相等时取到极值的不等式均可做此用途.

比如 \(\frac{a}{b}+\frac{b}{a}\) .

其他的一些想法包括在 \(\mathbb{R}\) 上判断是否为整数, 以及在 \(\mathbb{C}\) 上判断幅角等等.

回到刚才的问题上, 利用 \(fft\) , 我们可以计算每一个起始点的点积并进行匹配, 那如果要考虑通配符又应当如何呢.

或许可以对于每种字符分开考虑.

还有好几种 \(\text{fft}\) 做法,但我懒得写了,把一些神秘草稿扔上来,至于谁快直接看 yosupo 就行了.

一些精度分析
  1. \((a-b)^2ab\)

\(O(\frac{7}{2}E(n))\)

值域 \(n|\Sigma|^4\)

  1. \(\frac{a}{b}+\frac{b}{a}\)

\(O(E(n))\)

值域

\(i\) 个字符映射到 \((1+eps)^i\) 应该是比较优的.

此时是 \(n(1+eps)^{|\Sigma|}\frac{1}{eps^2}\) 取这玩意的极值

大概是 \(n|\Sigma|^2\) 这个级别

  1. \(\frac{a}{b}\)

\(O(\frac{1}{2}E(n))\)

值域 \(\frac{n}{p}\) 其中 \(p\) 为错误率, 要得到那种一辈子不会错的东西有点难, 抢最优解还是可以的.

  1. \(\omega_a\omega_b\)

\(O(E(n))\)

这个我真的不太会分析, 应该和 \(\frac{a}{b}\) 的情况类似.

压位加速

\(?\) 可以 \(O(\frac{nm}{w})\)

后面忘了

多字符通配

\(\text{*}\)

\(\text{*}\) 的情况 (不妨假设为 \(P\) )

function match(string T,string P) -> bool
    let n = |T|, m = |P|
    if n == 0 then
        if m == 0 then
            return true
        return P[m-1] == '*' and match(T,P[0,m-1))
    if m == 0 then
        return T[n-1] == '*' and match(T[0,n-1),P)
    if P[m-1] == '*' or T[n-1] == '*' then
        return match(T[0,n),P[0,m-1)) or match(T[0,n-1),P[0,m))
    if T[n-1] == P[m-1] or P[m-1] == '?' or T[n-1] == '?' then
        return match(T[0,n-1),P[0,m-1)) 
    return false

两侧均带 \(\text{*}\) 的情况

若两侧均带 \(\text{*}\), 则两侧从第一个 \(\text{*}\) 到最后一个 \(\text{*}\) 之间的部分必然可以匹配, 因此仅仅剩下无 \(\text{*}\) 的前缀匹配, 这是易于做的.

更复杂的模式

正则表达式

相似度匹配

一些相关的题目

luogu P4173 残缺的字符串

[CQOI2014] 通配符匹配

CF1344G Substring Search

CF1975G Zimpha Fan Club

posted @ 2026-03-26 23:44  QedDust  阅读(15)  评论(0)    收藏  举报