字符串
一、最小表示法:找循环字符串的"最小值"
什么是最小表示法?简单说,对于一个字符串S,它的循环移位(比如将"abcd"左移一位变成"bcda")有很多种,最小表示法就是其中字典序最小的那个。
比如字符串"abba",它的循环移位有"abba"、"bbaa"、"baab"、"aabb",其中字典序最小的是"aabb",这就是它的最小表示。
算法核心思路
最小表示法的高效求解依赖于两个指针和一个匹配长度变量,具体步骤如下:
- 初始化:设两个指针i=0,j=1(表示两个候选起始位置),匹配长度k=0,字符串长度为N。
- 比较字符:比较S[(i+k)%N]和S[(j+k)%N](取模是为了处理循环移位):
- 若两字符相等:k++,继续比较下一位;
- 若S[(i+k)%N] > S[(j+k)%N]:说明从i开始的字符串更"大",可以直接淘汰i到i+k的所有位置,令i=i+k+1,k重置为0;
- 若S[(i+k)%N] < S[(j+k)%N]:同理,淘汰j到j+k的位置,令j=j+k+1,k重置为0。
- 终止条件:当i或j超过N时,较小的那个指针就是最小表示的起始位置。
为什么高效?
这个算法的关键是指针永不后退,每次"淘汰"操作至少让指针前进1位。因此i和j的总移动距离不超过2N,每个字符最多被比较常数次,整体时间复杂度是O(N),线性高效。
二、Z函数:快速找前缀匹配长度
Z函数(Z-function)是字符串前缀匹配的利器,定义如下:对于字符串s,Z[i]表示s与s[i:](从i开始的后缀)的最长公共前缀长度,且规定Z[0]=0。
举个例子,对于s= "aaaabaaaab",它的Z数组是[0,3,2,1,0,5,3,2,1,0]:
- Z[1]=3:s[0..2]("aaa")与s[1..3]("aaa")匹配;
- Z[5]=5:s[0..4]("aaaab")与s[5..9]("aaaab")完全匹配。
算法核心思路
计算Z数组的关键是维护一个"当前最右匹配段"[l, r](即s[l..r]是s的前缀),利用已计算的Z值减少重复比较:
- 初始化:l=0,r=0(初始无匹配段),从i=1开始计算Z[i]。
- 分情况处理:
- 若i ≤ r:根据[l, r]的性质,s[i..r] = s[i-l..r-l],因此Z[i]至少为min(Z[i-l], r-i+1)。若Z[i-l] < r-i+1,则Z[i] = Z[i-l];否则需要从r+1开始暴力扩展。
- 若i > r:直接从s[i]开始暴力比较,计算Z[i]。
- 更新匹配段:计算完Z[i]后,若i+Z[i]-1 > r,则更新l=i,r=i+Z[i]-1。
应用场景
Z函数可用于解决前缀匹配相关问题,比如:
- 判断一个字符串是否是另一个的循环移位(结合最小表示法);
- 查找字符串中所有与某个前缀匹配的位置。
三、AC自动机
AC自动机(Aho-Corasick Automaton)是专门用于多模式匹配的算法,简单说就是给定一堆模式串(比如关键词),快速在一个文本串中找到所有出现的模式串。
比如在文章中高亮所有敏感词,就可以用AC自动机高效实现,比逐个用KMP匹配快得多。
核心特点
- 基于字典树(Trie)构建,同时增加了"失败指针"(类似KMP的next数组),用于在匹配失败时快速跳转,避免重复比较。
- 构建过程分三步:建字典树→求失败指针→模式匹配,整体时间复杂度与模式串总长度和文本串长度线性相关。
四、回文树:处理回文串的专属工具
回文树(Palindromic Tree,又称回文自动机)是专门用于统计和处理字符串中回文子串的结构,能高效找到所有不同的回文子串,以及它们的出现次数等信息。
核心特点
- 维护两种节点:分别对应长度为偶数和奇数的回文子串;
- 每个节点记录回文串的长度、后缀链接(类似失败指针)等信息;
- 构建过程中,每次添加一个字符,通过后缀链接快速找到以该字符结尾的最长回文子串,时间复杂度线性。

浙公网安备 33010602011771号