进阶数据结构应用-单词

目录

题目-单词

问题分析

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

  • 如果当前单词不是某个单词子串, 那么出现次数是 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;
}
相关推荐
历程里程碑1 小时前
Linux22 文件系统
linux·运维·c语言·开发语言·数据结构·c++·算法
ValhallaCoder9 小时前
hot100-二叉树I
数据结构·python·算法·二叉树
月挽清风10 小时前
代码随想录第十五天
数据结构·算法·leetcode
NEXT0611 小时前
前端算法:从 O(n²) 到 O(n),列表转树的极致优化
前端·数据结构·算法
会叫的恐龙13 小时前
C++ 核心知识点汇总(第六日)(字符串)
c++·算法·字符串
小妖66614 小时前
js 实现快速排序算法
数据结构·算法·排序算法
独好紫罗兰16 小时前
对python的再认识-基于数据结构进行-a003-列表-排序
开发语言·数据结构·python
wuhen_n16 小时前
JavaScript内置数据结构
开发语言·前端·javascript·数据结构
2401_8414956416 小时前
【LeetCode刷题】二叉树的层序遍历
数据结构·python·算法·leetcode·二叉树··队列
独好紫罗兰17 小时前
对python的再认识-基于数据结构进行-a002-列表-列表推导式
开发语言·数据结构·python