新闻中心

C++怎么实现一个后缀自动机(SAM)_C++高级字符串算法与子串问题

2025-12-09
浏览次数:
返回列表
后缀自动机能在线性时间内构建并解决子串相关问题,其核心是通过状态转移和后缀链接表示所有子串。

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 st; int last = 0; // 当前最后一个字符所在的状态 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

Songtell是第一个人工智能生成的歌曲含义库

Songtell 164 查看详情 Songtell

1. 不同子串个数

每个状态表示若干长度连续的子串,数量为 len - len(link)。累加所有状态即可。

long long count_distinct_substrings() { long long total = 0; for (int i = 1; i

2. 最短未出现子串

从初始状态开始 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教程 

搜索