信息发布→ 登录 注册 退出

C++怎么实现一个后缀自动机(SAM)_C++处理所有子串问题的强大字符串数据结构

发布时间:2025-12-05

点击量:
c++kquote>后缀自动机SAM是高效处理字符串子串问题的数据结构,能在O(n)时间内构建,支持查询子串出现次数、最长公共子串和不同子串个数;其核心由状态节点、转移边、后缀链接组成,通过扩展字符并维护len与link实现,关键步骤包括新建状态、沿后缀链接跳转、判断是否分裂状态以保证最小性;C++实现使用vector存储状态,map处理转移,常见应用有DP统计不同子串总数、反向传播计算出现频率、在SAM上匹配求两串最长公共子串等。

c++怎么实现一个后缀自动机(sam)_c++处理所有子串问题的强大字符串数据结构

后缀自动机(Suffix Automaton, SAM)是一种高效处理字符串子串问题的数据结构。它能在 O(n) 时间内构建,并支持快速查询所有子串的出现次数、最长公共子串、不同子串个数等问题。C++ 实现 SAM 的核心是理解其状态转移机制和后缀链接(suffix link)。

什么是后缀自动机

SAM 是一个最小化确定性有限自动机,能识别字符串的所有后缀对应的子串。每个状态代表一组具有相同“右端行为”的子串集合。关键组成部分包括:

  • 状态节点:包含 len(该状态表示的最长子串长度)、link(后缀链接指向更短的等价类)
  • 转移边 trans[c]:字符 c 的转移函数
  • last:当前添加字符后的最新状态

构建后缀自动机的步骤

每次向字符串末尾添加一个字符时,扩展自动机结构。主要逻辑如下:

  • 新建状态 cur,设置其 len 为 last->len + 1
  • 从 last 开始沿后缀链接向上跳,若没有 c 转移,则指向 cur
  • 遇到已有 c 转移的节点 p,设 q = p->trans[c]
  • 根据 len[q] 是否等于 len[p]+1 分裂状态或直接连接后缀链接

注意:分裂状态是为了保证 SAM 的最小性和正确性。

立即学习“C++免费学习笔记(深入)”;

C++ 实现代码

以下是简洁可运行的 SAM 实现:

Mistral AI Mistral AI

Mistral AI被称为“欧洲版的OpenAI”,也是目前欧洲最强的 LLM 大模型平台

Mistral AI 182 查看详情 Mistral AI ```cpp #include using namespace std;

struct State { int len, link; map trans; long long cnt; // 表示到达该状态的路径数(可用于统计子串数量) State() : len(0), link(-1), cnt(0) {} };

vector st; int last = 0;

void sam_init() { st.clear(); st.push_back(State()); last = 0; }

void sam_extend(char c) { int cur = st.size(); st.push_back(State()); st[cur].len = st[last].len + 1; int p = last;

while (p != -1 && !st[p].trans.count(c)) {
    st[p].trans[c] = cur;
    p = st[p].link;
}

if (p == -1) {
    st[cur].link = 0;
} else {
    int q = st[p].trans[c];
    if (st[p].len + 1 == st[q].len) {
        st[cur].link = q;
    } else {
        int clone = st.size();
        st.push_back(st[q]);         // 复制 q 状态
        st[clone].len = st[p].len + 1;
        while (p != -1 && st[p].trans[c] == q) {
            st[p].trans[c] = clone;
            p = st[p].link;
        }
        st[q].link = clone;
        st[cur].link = clone;
    }
}
last = cur;

}

<H3>常见应用与操作</H3>
<p>SAM 构建完成后可以解决多种问题:</p>
<ul>
  <li><strong>不同子串个数</strong>:从初始状态出发,每条路径对应唯一子串。可用 DP 计算:f[u] = 1 + Σ f[v](v 是 u 的转移目标)</li>
  <li><strong>每个子串出现次数</strong>:对每个状态标记是否为终止状态(出现在原串结尾),然后沿后缀链接反向传播计数</li>
  <li><strong>最长公共子串(两个串)</strong>:在 SAM 上匹配第二个串,维护当前匹配长度和状态,不断通过后缀链接调整</li>
</ul>

<p>例如统计不同子串总数:</p>
```cpp
long long count_distinct_substrings() {
    long long total = 0;
    for (int i = 1; i < st.size(); i++) {
        total += st[i].len - st[st[i].link].len;
    }
    return total;
}

基本上就这些。掌握 SAM 关键在于理解状态含义和分裂条件。实现时注意 map 可换成数组(仅限小字符集),提升性能。

以上就是C++怎么实现一个后缀自动机(SAM)_C++处理所有子串问题的强大字符串数据结构的详细内容,更多请关注其它相关文章!


相关文章: 将HTML Canvas内容转换为可上传的图像文件(File对象)  cad如何更改注释性对象的比例_cad注释性比例调整方法  css子元素高度不一致导致布局错位怎么办_使用align-items:stretch解决高度差异  一加手机拍照效果不好怎么办 一加哈苏影像调校与专业模式使用教程【高手篇】  age动漫网站入口 age动漫官网直接访问入口  Typer应用中灵活处理命令行参数的令牌化与解析  浏览器打开即用 美图秀秀网页版入口  CSS自定义字体样式被系统字体替换怎么办_font-face方式指定font-display控制渲染策略  AWS EC2实例间SQL Server连接超时:安全组配置与故障排除指南  微信群消息显示延迟如何解决 微信群消息刷新优化方法  汽水音乐在线版入口_汽水音乐网页播放手册  Python getattr() 异常处理深度解析:避免程序意外退出  整合Supabase认证与Django模型:跨模式迁移的解决方案  J*a TimerTask中HashMap意外清空的深层原因与解决方案  飞书妙记怎样用语音转文字速记_飞书妙记用语音转文字速记【速记方法】  sublime怎么设置启动时打开的窗口_sublime会话管理与热退出  C++如何进行游戏物理模拟_使用Box2D库为C++游戏添加2D物理效果  Golang如何使用bytes.Split分割字节切片_Golang bytes切片分割方法  1688商家版怎样分析买家画像精准供货_1688商家版分析买家画像精准供货【供货策略】  J*aScript Promise链中如何正确终止后续.then执行并处理错误  在WordPress中通过REST API获取BasicAuth保护的远程文章  使用PHP从URL路径中提取倒数第二个片段  Django通过AJAX异步上传图片并保存至模型的完整指南  谷歌浏览器如何快速清除某个网站的数据_Chrome网站缓存清理方法  Golang如何使用buffered channel提高性能_Golang buffered channel优化技巧  Python:递归比较文件夹内容并找出特定类型文件的差异  深入理解J*a编译器的兼容性选项:从-source到--release  126邮箱账号注册 电脑版登录入口  谷歌浏览器一键优化方案_谷歌浏览器直达主页极速不卡版  Tabulator表格中精确实现日期时间排序的指南  将JSON对象数组转置为键值对列表的实用指南  TikTok网页版直接登录 TikTok网页端官方平台入口  Yii2模块参数配置指南:正确声明与访问模块级配置  12306几点到几点不能订票? | 官方最新系统维护时间全解析  AO3镜像入口大全 AO3网页版内容访问全集  iwriter统一登录平台 iwrite账号密码登录页面  Golang如何通过reflect操作map_Golang reflect map操作与遍历技巧  抖音商城签到领现金是真的吗_抖音商城签到奖励与提现说明  使用Python高效删除Word宏并转换DOCM为DOCX格式  必由学官方网站入口 必由学学生教师共用登录通道  如何使 Jest 模拟函数默认抛出错误以提高测试效率  SteamMachine定价或为699美元 大家想入手吗?  微博网页版首页入口 微博电脑端官网登录链接  如何优雅地解决Livewire文件上传难题?SpatieLivewireFilepond让一切变得简单  《铁拳8》黑皮辣妹新实机:元气满满的18岁少女!  J*aScript教程:根据元素文本内容动态设置背景色  支付宝解绑银行卡步骤_支付宝如何解除绑定银行卡  Python中高效且防溢出的双曲正弦计算:基于对数空间的优化策略  解决 Vaadin 8 中大文件音频播放与定位时出现的 IOException  腾讯QQ邮箱官方网站_QQ邮箱网页版在线登录 

在线客服
服务热线

服务热线

4008988990

微信咨询
二维码
返回顶部
×二维码

截屏,微信识别二维码

打开微信

微信号已复制,请打开微信添加咨询详情!