c++ AC自动机

概念

AC 自动机(Aho-Corasick 自动机)是一种高效的字符串匹配算法,特别适用于从文本中同时查找多个模式串的场景。它结合了 Trie 树(前缀树)和 KMP(Knuth-Morris-Pratt)算法 的思想,可以在 O(n+m+z) 的时间复杂度内完成任务,其中:

  • n:文本长度
  • m:所有模式串的总长度
  • z:匹配到的总结果数

步骤

  1. 构建 Trie 树
    将所有模式串插入 Trie 树,以便快速进行前缀匹配。

  2. 构建失配指针
    使用广度优先搜索(BFS)为每个节点建立失配指针,使得在匹配失败时可以快速跳转到另一个可能的匹配状态。

  3. 搜索目标文本
    遍历目标文本,利用 Trie 树和失配指针同时匹配多个模式串。

应用场景

  • 敏感词过滤:检测并替换敏感词。

  • DNA 序列分析:在基因组序列中查找多个目标序列。

  • 网络安全:分析日志中的潜在攻击模式。

  • 全文搜索:从文档中快速定位关键词。

示例

在一段文本中匹配多个关键词,并统计每个关键词出现的次数。

#include <iostream>
#include <queue>
#include <vector>
#include <string>
#include <unordered_map>

using namespace std;

const int ALPHABET_SIZE = 26; // 假设仅处理小写字母

struct TrieNode {
    vector<TrieNode*> children;
    TrieNode* fail;    // 失配指针
    int count;         // 表示当前模式串匹配次数
    TrieNode() : children(ALPHABET_SIZE, nullptr), fail(nullptr), count(0) {}
};

class ACAutomaton {
private:
    TrieNode* root;

public:
    ACAutomaton() {
        root = new TrieNode();
    }

    // 插入模式串
    void insert(const string& word) {
        TrieNode* node = root;
        for (char c : word) {
            int index = c - 'a';
            if (!node->children[index]) {
                node->children[index] = new TrieNode();
            }
            node = node->children[index];
        }
        node->count++; // 标记模式串的结束
    }

    // 构建失配指针
    void build() {
        queue<TrieNode*> q;
        root->fail = root; // 根节点的失配指针指向自身
        for (int i = 0; i < ALPHABET_SIZE; ++i) {
            if (root->children[i]) {
                root->children[i]->fail = root;
                q.push(root->children[i]);
            } else {
                root->children[i] = root; // 优化:虚拟节点指向根节点
            }
        }

        while (!q.empty()) {
            TrieNode* current = q.front();
            q.pop();
            for (int i = 0; i < ALPHABET_SIZE; ++i) {
                TrieNode* child = current->children[i];
                if (child) {
                    child->fail = current->fail->children[i];
                    q.push(child);
                } else {
                    current->children[i] = current->fail->children[i];
                }
            }
        }
    }

    // 匹配文本并统计结果
    unordered_map<string, int> search(const string& text, const vector<string>& patterns) {
        TrieNode* node = root;
        unordered_map<string, int> result;

        // 初始化结果计数
        for (const string& pattern : patterns) {
            result[pattern] = 0;
        }

        for (char c : text) {
            int index = c - 'a';
            node = node->children[index];
            TrieNode* temp = node;

            // 遍历失配链以统计所有可能的匹配
            while (temp != root) {
                if (temp->count > 0) {
                    result[patterns[temp->count - 1]] += temp->count;
                }
                temp = temp->fail;
            }
        }
        return result;
    }
};

int main() {
    ACAutomaton ac;
    vector<string> patterns = {"he", "she", "his", "hers"};
    string text = "ahishers";

    // 构建 AC 自动机
    for (const string& pattern : patterns) {
        ac.insert(pattern);
    }
    ac.build();

    // 搜索文本
    unordered_map<string, int> result = ac.search(text, patterns);

    // 输出匹配结果
    for (const auto& entry : result) {
        cout << entry.first << ": " << entry.second << endl;
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值