数据结构篇章

kmp字符串

在这里插入图片描述
在这里插入图片描述
一:借助于前缀&后缀的理解,next[i]的构造是找到前缀等于后缀的那个位置
p[1,j]=p[i-j+1,i]前缀和后缀进行匹配操作
二:构造next[i]=value 的例子
其中value表示前缀和后缀相同的字母的数量
另外i 表示指针指到哪个元素下
其中的next[1] 和next[2]显然不满足,所以他们的value都为0
构建next数组
借鉴大佬写的:

// 构造next数组
    for (int i = 2, j = 0; i <= n;i ++) {
        while (j && p[i] != p[j+1])//直到匹配
            j = ne[j];// 对模式串进行匹配,如果没有匹配成功,j变成ne[j]的位置(就是上一个next的位置)  比如
        if (p[i] == p[j+1])
            j++;// 匹配成功,j到后一位
        ne[i] = j;// 记录匹配成功的i位和j位的对应关系
    }

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 1e6 + 5;
int n, m;
char p[N], s[N];
int ne[N];
int main()
{
    cin >> n >> p + 1 >> m >> s + 1;
    for(int i = 2, j = 0; i <= m; i ++ )
    {
        while(j && p[i] != p[j + 1]) j = ne[j];
        if(p[i] == p[j + 1]) j ++;
        ne[i] = j;
    }
    
    for(int i = 1, j = 0; i <= m; i ++)
    {
        while(j && s[i] != p[j + 1]) j = ne[j];
        if(s[i] == p[j + 1]) j ++;
        if(j == n)
        {
            printf("%d ", i - n);
            j = ne[j];
        }
    }
}

tire 字符串的统计

在这里插入图片描述
在这里插入图片描述一:trie树能够高效存储和查找字符串集,是一种多叉树的结构,每个节点保存一个字符,一条路径表示一个字符串。
二:Trie 树中每个节点存储一个字符,从根节点到叶节点的一条路径存储一个字符串
三:Trie 树的生成过程,就是不断将字符串插入树中。
四:Trie 树最基本的作用是在树上查找字符串
以插入字符串 him 为例,过程
大佬源码
(大佬图)
在这里插入图片描述

#include<iostream>
using namespace std;
const int N = 100010;
int idx; // 各个节点的编号,根节点编号为0
int son[N][26];//Trie 树本身
//cnt[x] 表示:以 编号为 x 为结尾的字符串的个数
int cnt[N];

int n;

void insert(string s){
    int p = 0;//指向根节点
    for(int i = 0; i < s.size(); i++){
        //将当前字符转换成数字(a->0, b->1,...)
        int u = s[i] - 'a';
        //如果数中不能走到当前字符
        //为当前字符创建新的节点,保存该字符
        if(!son[p][u])
            // 新节点编号为 idx + 1
            son[p][u] = ++idx;
        p = son[p][u];
    }
    //这个时候,p 等于字符串 s 的尾字符所对应的 idx
    //cnt[p] 保存的是字符串 s 出现的次数
    //故 cnt[p] ++
    cnt[p] ++;
}

int query(string s){
    int p = 0;//指向根节点
    for(int i = 0; i < s.size(); i++){
        //将当前字符转换成数字(a->0, b->1,...)
        int u = s[i] - 'a';
        //如果走不通了,即树中没有保存当前字符
        //则说明树中不存在该字符串
        if(!son[p][u]) 
            return 0;
        //指向下一个节点
        p = son[p][u];
    }
    //循环结束的时候,p 等于字符串 s 的尾字符所对应的 idx
    // cnt[p] 就是字符串 s 出现的次数
    return cnt[p];
}

int main(){
    cin >> n;
    string s;
    char q;
    while(n--){
        cin >> q >> s;
        if(q == 'I'){
            //插入操作
            insert(s);
        }
        else{
            //查询操作
            cout << query(s) << endl;
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一直爱莲子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值