进阶数据结构应用-单词

目录

题目-单词

问题分析

目标是每个单词出现的次数, 分为两类

  • 如果当前单词不是某个单词子串, 那么出现次数是 1 1 1
  • 如果当前单词是某个单词的子串, 如何计算次数?

我们可以统计这样一个数值, 对于串 s s s, 有多少个前缀是以 s s s为后缀的 , 这个值就是答案

对于字符串 t t t, 某一个前缀的后缀 是 s s s, 那么答案需要累计

如何计算?

对于当前串 s s s, 计算当前后缀 和哪些前缀匹配, 在AC自动机直接可以迭代计算

fail[u], fail[fail[u]], fail[fail[fail[u]]]...都是和当前后缀匹配的前缀

递推思想, 对于当前后缀出现次数 假设是 x x x, 将前面的前缀全部累加 + x +x +x

例如某个后缀是aaa, 与之匹配的aa前缀也需要 + 1 +1 +1, 与aa匹配的前缀a也需要 + 1 +1 +1

因此直接按照AC自动机的fail指针拓扑序逆序递推就能得到答案

算法步骤

  • 将读入的字符串加入到Trie中, 假设当前遍历的是节点 u u u, u u u作为后缀出现次数累加cnt[u]++
  • 假设当前添加的是第 k k k个字符串, 当字符串添加完毕后, 记录结尾的Trie指针id[k] = u
  • 构建AC自动机
  • 按照拓扑序逆序从后向前递推 , 因为后面的是更长的后缀 , cnt[fail[i]] += cnt[i]
  • 按照 i d id id计算每个字符串出现的次数

代码实现

cpp 复制代码
#include <bits/stdc++.h>

using namespace std;

const int N = 210, M = 1e6 + 10;

int n;
int tr[M][26], idx;
int f[M];
int q[M], h, t;
int fail[M], id[N];

void insert(string &s, int k) {
    int p = 0;
    for (int i = 0; s[i]; ++i) {
        int c = s[i] - 'a';
        if (!tr[p][c]) tr[p][c] = ++idx;
        p = tr[p][c];
        // 因为p是代表某个后缀, 因此需要在p = tr[p][c]后面f[p]++
        f[p]++;
    }

    id[k] = p;
}

void build() {
    h = 0, t = -1;
    for (int i = 0; i < 26; ++i) {
        if (tr[0][i]) q[++t] = tr[0][i];
    }

    while (h <= t) {
        int u = q[h++];
        for (int i = 0; i < 26; ++i) {
            int v = tr[u][i];
            if (!v) continue;
            int j = fail[u];
            while (j && !tr[j][i]) j = fail[j];
            if (tr[j][i]) j = tr[j][i];
            fail[v] = j;
            q[++t] = v;
        }
    }
}


int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);

    cin >> n;
    string s;
    for (int i = 0; i < n; ++i) {
        cin >> s;
        insert(s, i);
    }

    build();

    for (int i = t; i >= 0; --i) {
        int u = q[i];
        f[fail[u]] += f[u];
    }

    for (int i = 0; i < n; ++i) cout << f[id[i]] << '\n';

    return 0;
}
相关推荐
MegaDataFlowers44 分钟前
206.反转链表
数据结构·链表
CN-Dust2 小时前
【C++】while语句例题专题
数据结构·c++·算法
xieliyu.4 小时前
Java手搓数据结构:从零模拟实现无头双向非循环链表
java·数据结构·链表
如何原谅奋力过但无声5 小时前
【灵神高频面试题合集01-03】相向双指针、滑动窗口
数据结构·python·算法·leetcode
jieyucx7 小时前
Go 数据结构入门:线性表、顺序表、链表
数据结构·链表·golang
阿维的博客日记7 小时前
zset为什么要用到skiplist+Dict的数据结构
数据结构·skiplist
编程之升级打怪8 小时前
KMP查询算法的匹配串的前缀后缀相同的最大长度
数据结构
没文化的阿浩10 小时前
【数据结构】排序(2)——直接选择排序、堆排序
数据结构·算法·排序算法
承渊政道11 小时前
【动态规划算法】(子数组系列问题建模与解题思路精讲)
数据结构·c++·学习·算法·leetcode·动态规划·哈希算法
冷小鱼11 小时前
数据结构:从“生活常识“到“工程实战“
数据结构