进阶数据结构应用-单词

目录

题目-单词

问题分析

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

  • 如果当前单词不是某个单词子串, 那么出现次数是 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;
}
相关推荐
啦哈拉哈2 小时前
【Python】知识点零碎学习1
数据结构·python·算法
Han.miracle2 小时前
算法--003快乐数
数据结构·算法·快乐数
永远都不秃头的程序员(互关)2 小时前
查找算法深入分析与实践:从线性查找到二分查找
数据结构·c++·算法
良木生香3 小时前
【数据结构-初阶】详解线性表(1)---顺序表
数据结构
CoderYanger3 小时前
C.滑动窗口——2762. 不间断子数组
java·开发语言·数据结构·算法·leetcode·1024程序员节
好风凭借力,送我上青云4 小时前
哈夫曼树和哈夫曼编码
c语言·开发语言·数据结构·c++·算法·霍夫曼树
秋深枫叶红4 小时前
嵌入式第三十篇——数据结构——哈希表
数据结构·学习·算法·哈希算法
✎ ﹏梦醒͜ღ҉繁华落℘4 小时前
编程基础--数据结构
数据结构·算法
mifengxing5 小时前
B树的定义以及插入和删除
数据结构·b树