“给定文本 $T$ 和非空模式 $P$,令 $m= P $,先计算模式的 前缀函数 $\pi$。每次读取新字符前维护 $0\le q<m$:已读文本的后缀中,等于 $P$ 的某个真前缀的最长长…”
形式陈述
给定长度为
也就是说,
整个数组可由下列回退过程在线性时间求出:
π[0] = 0
for i = 1, 2, ..., n - 1:
j = π[i - 1]
while j > 0 and s[i] != s[j]:
j = π[j - 1]
if s[i] == s[j]:
j = j + 1
π[i] = j
若字符串为空,前缀函数就是空数组;实现时应把这一接口情形置于循环之外处理。
直觉
一个 border 是同时出现在字符串两端的同一段内容。已知
如果这两个字符失配,并不需要把候选降到零。任何仍可能延长的候选,必须既是
会按长度从大到小枚举全部可行 border,而不会漏掉中间候选。这个“最长 border 的最长 border”链,就是前缀函数压缩重复结构的方式。
每轮的 while 沿候选链排除无法延长的 border,直到找到最长可延长候选,或退回长度零。随后的字符比较把候选延长一位;若长度零仍失配,就令
线性复杂度来自候选长度的记账:外层每前进一步,while 中每次回退都会严格减小
例子与边界
字符串 aabaaab 的前缀函数为
前五个字符 aabaa 的最长 border 是 aa,所以 a 时,长度 b,发生失配;回退到 a 延长,于是 b 时,aa 可延长为 aab,得到
前缀函数保存的是长度,不是字符下标。候选长度为 0 同时表示空 border 和没有更短候选,不代表首字符已经匹配。
若要列出整个字符串长度
推论与应用
词与序列给出离散对象,前缀函数则为每个前缀组织 border 链。KMP把这条链用作模式失配后的状态回退。
前缀出现次数也能由同一棵失败链汇总。先把每个位置贡献给其 # 和文本 P#T,则拼接串上值等于
前缀函数与Z 函数都编码字符串前缀与其他位置的重合信息,可在线性时间互相恢复;它们记录的长度含义不同,各有相应的构造算法。若要对固定全文回答许多模式查询,FM-index 等全文索引则把预处理工作放在文本一侧。
参考资料
- Donald E. Knuth, James H. Morris Jr., and Vaughan R. Pratt, “Fast Pattern Matching in Strings,” SIAM Journal on Computing 6(2), 1977, pp. 323–350.
- Dan Gusfield, Algorithms on Strings, Trees, and Sequences, Cambridge University Press, 1997, Ch. 1.
- Frantisek Franek, W. F. Smyth and Xinfang Wang, “The Role of the Prefix Array in Sequence Analysis: A Survey”, 2017,讨论 border array 与 prefix array 的线性互换;该文的 prefix array 指本库的 Z 数组。
- cp-algorithms contributors, “Prefix Function,” Algorithms for Competitive Programming, accessed August 9, 2026.