Rust回文树详解(从零开始掌握回文自动机的Rust实现)

简介: 本教程详解如何用Rust语言实现回文树(回文自动机),涵盖核心概念、节点结构设计与动态构建过程。通过清晰的代码示例,带你掌握高效处理回文子串统计的方法,适合Rust初学者和算法爱好者学习与实践。

在字符串处理领域,Rust回文树(也称为回文自动机)是一种高效的数据结构,用于快速统计和查询字符串中所有不同的回文子串。本教程将手把手教你如何用Rust语言实现一个完整的回文树,即使你是Rust初学者也能轻松上手。

什么是回文树?

回文树(Palindromic Tree),又称Eertree,是由Mikhail Rubinchik在2015年提出的一种数据结构。它能够在线性时间内构建,并支持动态添加字符、统计不同回文子串数量、查询最长回文后缀等操作。

回文树的核心思想

回文树包含两类节点:

  • 奇根节点:代表长度为-1的虚拟回文串(用于处理奇数长度回文)
  • 偶根节点:代表长度为0的空回文串(用于处理偶数长度回文)

每个节点存储以下信息:

  • 回文串的长度
  • 指向其最长回文后缀的fail指针
  • 子节点映射(通过字符跳转)
  • 出现次数(可选)

Rust实现步骤

下面我们用字符串处理Rust的方式逐步实现回文树。

1. 定义节点结构

#[derive(Default)]struct Node {    len: i32,               // 回文串长度    fail: usize,            // fail指针    next: [usize; 26],      // 子节点(假设只处理小写字母)    count: usize,           // 出现次数}impl Node {    fn new(len: i32) -> Self {        Node {            len,            fail: 0,            next: [0; 26],            count: 0,        }    }}

2. 定义回文树结构

struct PalindromicTree {    nodes: Vec<Node>,    last: usize,            // 当前最长回文后缀对应的节点    s: Vec<u8>,             // 输入字符串的字符数组    n: usize,               // 当前处理到的位置}impl PalindromicTree {    fn new() -> Self {        let mut nodes = Vec::new();        // 节点0:偶根(长度0)        nodes.push(Node::new(0));        // 节点1:奇根(长度-1)        nodes.push(Node::new(-1));                // 奇根的fail指向自己        nodes[1].fail = 1;        // 偶根的fail指向奇根        nodes[0].fail = 1;                PalindromicTree {            nodes,            last: 0,            s: vec![0], // 添加哨兵            n: 0,        }    }}

3. 实现扩展函数

关键在于找到当前位置能形成的新回文串:

impl PalindromicTree {    fn extend(&mut self, c: u8) {        self.s.push(c);        self.n += 1;                let ci = (c - b'a') as usize;        let mut cur = self.last;                // 找到满足 s[n - len[cur] - 1] == s[n] 的cur        while self.s[self.n - self.nodes[cur].len as usize - 1] != c {            cur = self.nodes[cur].fail;        }                if self.nodes[cur].next[ci] != 0 {            // 已存在该回文串            self.last = self.nodes[cur].next[ci];            self.nodes[self.last].count += 1;            return;        }                // 创建新节点        let new_node = self.nodes.len();        self.nodes.push(Node::new(self.nodes[cur].len + 2));        self.nodes[cur].next[ci] = new_node;                // 设置fail指针        if self.nodes[new_node].len == 1 {            // 长度为1,fail指向偶根            self.nodes[new_node].fail = 0;        } else {            // 找到最长回文后缀            let mut tmp = self.nodes[cur].fail;            while self.s[self.n - self.nodes[tmp].len as usize - 1] != c {                tmp = self.nodes[tmp].fail;            }            self.nodes[new_node].fail = self.nodes[tmp].next[ci];        }                self.last = new_node;        self.nodes[self.last].count = 1;    }}

4. 使用示例

fn main() {    let s = "ababa";    let mut tree = PalindromicTree::new();        for c in s.bytes() {        tree.extend(c);    }        // 不同回文子串数量 = 节点数 - 2(减去两个根节点)    println!("不同回文子串数量: {}", tree.nodes.len() - 2);        // 输出所有回文串长度    for (i, node) in tree.nodes.iter().enumerate() {        if i > 1 { // 跳过根节点            println!("回文串长度: {}, 出现次数: {}", node.len, node.count);        }    }}

为什么选择Rust实现回文自动机?

使用Rust算法实现回文树有诸多优势:

  • 内存安全:避免C++中常见的指针错误
  • 零成本抽象:性能接近C/C++
  • 强大的类型系统:编译期捕获错误
  • 所有权模型:自动管理内存,无需垃圾回收

总结

通过本教程,你已经掌握了Rust回文树的基本原理和完整实现。回文自动机是处理回文相关问题的强大工具,在竞赛编程和实际应用中都有广泛用途。建议你动手实践,尝试添加更多功能如输出具体回文串、处理Unicode字符等。

记住,掌握字符串处理Rust技巧不仅能提升算法能力,还能加深对Rust语言特性的理解。继续练习,你将成为Rust算法高手!

来源:

https://www.vpshk.cn/

相关文章
|
7天前
|
数据采集 人工智能 安全
|
16天前
|
云安全 监控 安全
|
2天前
|
机器学习/深度学习 人工智能 前端开发
构建AI智能体:七十、小树成林,聚沙成塔:随机森林与大模型的协同进化
随机森林是一种基于决策树的集成学习算法,通过构建多棵决策树并结合它们的预测结果来提高准确性和稳定性。其核心思想包括两个随机性:Bootstrap采样(每棵树使用不同的训练子集)和特征随机选择(每棵树分裂时只考虑部分特征)。这种方法能有效处理大规模高维数据,避免过拟合,并评估特征重要性。随机森林的超参数如树的数量、最大深度等可通过网格搜索优化。该算法兼具强大预测能力和工程化优势,是机器学习中的常用基础模型。
266 155
|
3天前
|
机器学习/深度学习 人工智能 前端开发
构建AI智能体:六十九、Bootstrap采样在大模型评估中的应用:从置信区间到模型稳定性
Bootstrap采样是一种通过有放回重抽样来评估模型性能的统计方法。它通过从原始数据集中随机抽取样本形成多个Bootstrap数据集,计算统计量(如均值、标准差)的分布,适用于小样本和非参数场景。该方法能估计标准误、构建置信区间,并量化模型不确定性,但对计算资源要求较高。Bootstrap特别适合评估大模型的泛化能力和稳定性,在集成学习、假设检验等领域也有广泛应用。与传统方法相比,Bootstrap不依赖分布假设,在非正态数据中表现更稳健。
206 105
|
10天前
|
SQL 自然语言处理 调度
Agent Skills 的一次工程实践
**本文采用 Agent Skills 实现整体智能体**,开发框架采用 AgentScope,模型使用 **qwen3-max**。Agent Skills 是 Anthropic 新推出的一种有别于mcp server的一种开发方式,用于为 AI **引入可共享的专业技能**。经验封装到**可发现、可复用的能力单元**中,每个技能以文件夹形式存在,包含特定任务的指导性说明(SKILL.md 文件)、脚本代码和资源等 。大模型可以根据需要动态加载这些技能,从而扩展自身的功能。目前不少国内外的一些框架也开始支持此种的开发方式,详细介绍如下。
723 5
|
13天前
|
人工智能 自然语言处理 API
一句话生成拓扑图!AI+Draw.io 封神开源组合,工具让你的效率爆炸
一句话生成拓扑图!next-ai-draw-io 结合 AI 与 Draw.io,通过自然语言秒出架构图,支持私有部署、免费大模型接口,彻底解放生产力,绘图效率直接爆炸。
813 153