新闻中心
C++怎么实现一个后缀自动机(SAM)_C++高级字符串算法与子串问题
后缀自动机能在线性时间内构建并解决子串相关问题,其核心是通过状态转移和后缀链接表示所有子串。

后缀自动机(Suffix Automaton,简称 SAM)是处理字符串子串问题的高效数据结构。它能在 O(n) 时间内构建,并支持快速解决子串计数、最长公共子串、不同子串个数等问题。下面介绍 C++ 中如何实现一个基础的后缀自动机。
什么是后缀自动机
后缀自动机是一个有向图,其中每个节点代表原字符串某个子串的“状态”,边表示在该状态后添加一个字符能转移到的新状态。SAM 的核心性质包括:
- 所有从初始状态可达的路径,对应原串的所有子串。
- 总状态数不超过 2n,转移边数不超过 3n。
- 每个状态记录了该状态所代表子串的最长长度(len)和最小长度(通过 link 树推导)。
核心结构与变量定义
我们用结构体维护 SAM 的每个节点,主要包含以下字段:
- len:当前状态能表示的最长子串长度。
- link:后缀链接(suffix link),指向另一个状态,表示当前状态的最长串的真后缀中最长的可接受状态。
- next[26]:转移数组,记录添加字符 a~z 后的下一个状态。
// 假设只处理小写字母 struct State { int len; // 最长子串长度 int link; // 后缀链接 int next[26]; // 转移边 State() { len = 0; link = -1; for (int i = 0; i
全局维护一个状态数组和相关变量:
立即学习“C++免费学习笔记(深入)”;
vector
最后一个字符所在的状态
int sz = 0; // 状态总数构建后缀自动机
每次添加一个字符时,创建新状态并更新后缀链接。算法核心步骤如下:
void sam_init() { st.push_back(State()); sz++; last = 0; }
void sam_extend(char c) { int cur = sz++; st.push_back(State()); st[cur].len = st[last].len + 1; int p = last;
// 从 last 开始,沿着后缀链接走,直到根或已有 c 转移
while (p != -1 && st[p].next[c - 'a'] == -1) {
st[p].next[c - 'a'] = cur;
p = st[p].link;
}
if (p == -1) {
st[cur].link = 0;
} else {
int q = st[p].next[c - 'a'];
if (st[p].len + 1 == st[q].len) {
st[cur].link = q;
} else {
int clone = sz++;
st.push_back(st[q]); // 复制 q 的信息
st[clone].len = st[p].len + 1;
// 将 q 的转移复制,但不改变 len 和 link
while (p != -1 && st[p].next[c - 'a'] == q) {
st[p].next[c - 'a'] = clone;
p = st[p].link;
}
st[q].link = st[cur].link = clone;
}
}
last = cur;}
说明:
- 每次扩展字符 c,新建状态 cur,其最长长度为 last.len + 1。
- 从 last 沿着 link 往上跳,为没有 c 转移的状态添加指向 cur 的边。
- 若遇到已有 c 转移的状态 p,则检查目标状态 q 是否满足 len 条件。
- 若不满足(即 q 是被多个路径共享的复杂状态),则需分裂出一个 clone 状态来保证正确性。
常见应用示例
利用 SAM 可以高效求解多种问题:
Songtell
Songtell是第一个人工智能生成的歌曲含义库
164
查看详情
1. 不同子串个数
每个状态表示若干长度连续的子串,数量为 len - len(link)。累加所有状态即可。
long long count_distinct_substrings() { long long total = 0; for (int i = 1; i2. 最短未出现子串
从初始状态开始 BFS,找第一个缺失的字符转移,该字符即是最短未出现子串。
3. 最长公共子串(两个串)
对第一个串建 SAM,然后用第二个串在 SAM 上匹配,维护当前匹配长度和状态,不断沿 link 跳转以缩短匹配。
int longest_common_substring(string s, string t) { int res = 0, v = 0, l = 0; for (char c : t) { while (v && st[v].next[c-'a'] == -1) { v = st[v].link; l = st[v].len; } if (st[v].next[c-'a'] != -1) { v = st[v].next[c-'a']; l++; } res = max(res, l); } return res; }
基本上就这些。SAM 虽初看复杂,但掌握 extend 过程和 link 作用后,理解会清晰很多。关键是理解 clone 操作的意义:保持 DAG 中每个状态的 right 集合一致。
以上就是C++怎么实现一个后缀自动机(SAM)_C++高级字符串算法与子串问题的详细内容,更多请关注其它相关文章!
# 转换为
# 新山村网站推广方式优化
# 绵竹手机网站建设
# 福州网站建设策略
# 网游推广素材网站
# 南阳seo搜索优化
# 海淀网站建设推荐
# 网站推广有限公司
# 荆门关键词排名公司
# 昆明网站SEO厂家
# 襄阳网站推广哪个好点
# c++
# 最短
# 不超过
# 时间内
# 能在
# 与子
# 已有
# 如何实现
# 数据结构
# 第一个
# 后缀自动机
相关栏目:
【
科技资讯46185 】
【
网络学院92790 】
相关推荐:
Composer的 archive 命令怎么用_快速打包你的PHP项目及其Composer依赖
知乎APP怎么管理已购盐选内容_知乎APP盐选内容购买记录与查看方法
解决macOS上安装pyhdf时‘hdf.h’文件缺失的编译错误
蛙漫漫画官网在线入口 蛙漫全本漫画免费阅读平台
使用 Pandas 高效处理 .dat 文件:数据清洗与数值计算实战
中兴BladeV30怎样用测距估书架层高_iPhone中兴BladeV30测距估书架层高【家装参考】
win11 Snap Layouts怎么用 Win11窗口布局与分屏多任务高效指南【必学】
如何使用J*aScript精确选择并批量修改特定父元素下子链接的样式
c++项目目录结构应该如何组织_c++工程化项目结构规范
在哪找SublimeJ远程工具_SFTP插件配置教程
J*a里如何实现线程安全的懒加载单例_懒加载单例实现方法解析
Golang如何实现Web文件静态资源服务器_Golang静态资源服务器开发与实践
Tailwind CSS line-clamp 布局问题解析与修复指南
C++如何实现线程池_C++11手动实现一个简单的固定大小线程池
2306选座时如何选靠窗位置_12306选座靠窗座位查看方法解析
《GTA6》开发画面疑似泄露!这次可不是AI了
PowerPoint如何制作滚动字幕结尾彩蛋_PowerPoint路径动画实现平滑滚动字幕效果
Composer的 "licenses" 命令如何帮助你遵守开源协议_检查项目依赖的许可证合规性
夸克浏览器桌面版同步不了书签怎么处理 夸克浏览器跨设备同步异常解决方案
AO3最新入口2025公告_AO3中文官网合集
sublime怎么进行远程开发编辑_配置rsub/rmate实现sublime编辑服务器文件
修复二维数组索引越界异常:一维循环到二维坐标的正确映射
LocoySpider如何部署到云服务器_LocoySpider云部署的远程配置
小米Civi 4录制视频过暗_小米Civi 4亮度优化
汽水音乐在线解析 汽水音乐在线解析入口
大象笔记网页版入口 印象笔记网页版登录入口
MAC怎么安装Homebrew包管理器_MAC为开发者和高级用户安装命令行工具
漫蛙官网正版漫画入口 漫蛙2官方网页登录地址
创客贴用户入口官网登录 创客贴网页版电脑版系统
小红书怎么解除第三方平台绑定_小红书多平台登录解绑方法介绍
今日头条怎么同步内容到抖音_今日头条内容同步到抖音教程
Win11怎么设置鼠标主按键_Win11鼠标左右键功能互换
怎么在mac上运行html代码_mac运行html代码方法【指南】
Win11 USB传输速度慢怎么解决 Win11 USB驱动更新与设置
使用Python高效删除Word宏并转换DOCM为DOCX格式
神庙逃亡小游戏在线玩 神庙逃亡小游戏入口
excel如何生成目录 excel一键生成工作表目录超链接
Lar*el 8 多关键词数据库搜索优化实践
HuggingFaceEmbeddings中向量嵌入维度调整的限制与理解
深入理解J*aScript Promise异步执行与微任务队列
css绝对定位元素脱离父容器怎么办_确保父元素position非static
抖音网页版平台入口 抖音网页版官网在线访问教程
快手官方唯一登录入口 谨防山寨钓鱼网站
如何使用 Excel 发布器与 Power BI 分享 Excel 洞察
实现全屏滚动与导航点:专业教程
PostgreSQL海量数据高效导入策略:Python与Django实践指南
将JSON对象数组转置为键值对列表的实用指南
QQ邮箱官网登录入口 QQ邮箱网页版邮箱快速登录
必由学登录入口 必由学官方网站在线访问链接
sublime怎么预览Markdown渲染效果_Markdown Preview插件 for sublime教程


2025-12-09
浏览次数:次
返回列表