\(\mathcal{KMP算法}\)

实际上,完全没必要从\(S\)的每一个字符开始,暴力穷举每一种情况,\(Knuth、Morris\)和\(Pratt\)对该算法进行了改进,称为KMP算法。

而\(KMP\)的精髓在于,对于每次失配之后,我都不会从头重新开始枚举,而是根据我已经得知的数据,从某个特定的位置开始匹配;而对于模式串的每一位,都有唯一的“特定变化位置”,这个在失配之后的特定变化位置可以帮助我们利用已有的数据不用从头匹配,从而节约时间。

特点:1. \(i\) 不回退 2. \(j\) 回退的位置有讲究 3.构建一个辅助数组( \(nxt\) 数组)来跳过不必要的字符比较,从而提高搜索速度。

\(\mathcal{实现流程}\)

为了清楚地表述目的, \(T\) 与 \(S\) 失配前的部分作为 \(T'\) 来表述,此时寻找下一个开始匹配的标志头。而找到下一个标志头的方式为:

找到 \(T'\) 的最长相同前缀与后缀

\(\color{red}{这样找所有的前缀和后缀比较,是不是也是暴力穷举??那该怎么办呢??}\)

\(\color{red}{ans:当然是要用到动态规划递推啦。}\)

\(\mathcal{构建 Nxt 数组}\)

\(nxt\) 数组用于表示当前字符匹配失败时,模式串应该回退到哪个位置。对于模式串 \(p\) ,我们遍历其每个字符,并用一个指针 \(j\) 表示已匹配的字符数。当模式串中的两个字符匹配时,我们更新指针 \(j\) 的值,否则,我们回退 \(j\) 到 \(nxt[j]\) 的位置。通过这种方式,我们可以为模式串构建一个 \(nxt\) 数组,其中 \(nxt[i]\) 表示当模式串中第 \(i\) 个字符匹配失败时,应该回退到的位置。

\(\mathcal{实际字符匹配过程}\)

我们使用两个指针 \(i\) 和 \(j\) 分别遍历原字符串 \(s\) 和模式串 \(p\) 。如果当前字符匹配,则同时移动 \(i\) 和 \(j\) 。如果字符不匹配,我们根据 \(nxt\) 数组回退 \(j\) 的位置,直到找到匹配的字符或回退到模式串的开头。当 \(j\) 等于模式串长度 \(m\) 时,表示找到了一个匹配,输出匹配位置,并将 \(j\) 重置为 \(0\) 。

\(\mathcal{模板代码实现}\)

#include <iostream>
using namespace std;
const int N = 1e+6 + 10;
int nxt[N], n, m;
char p[N], s[N];
int main()
{
cin >> n >> s + 1 >> m >> p + 1;
// build next arraylist
for (int i = 2, j = 0; i <= m; i++)
{
while (j && p[i] != p[j + 1]) j = nxt[j];
if (p[i] == p[j + 1]) j++;
nxt[i] = j;
}
// marry the str
for (int i = 1, j = 0; i <= n; i++)
{
while (j && s[i] != p[j + 1]) j = nxt[j];
if (s[i] == p[j + 1]) j++;
if (j == m) {
cout << i - m << " ";
j = 0;
}
}
cout << endl;
return 0;
}

\(\mathcal{Trie\,树}\)

字典树是一种高效的字符串数据结构,尤其适用于处理大量字符串的时候,它通过将字符串的公共前缀合并在一起,节省空间并提高查询速度。

\(\mathcal{实现流程}\)

\(\mathcal{初始化变量和数据结构}\)

定义一个字典树结构( \(tree\) 数组)和一个记录字符串出现次数的数组( \(vis\) 数组)。同时定义一个计数器 \(flag\) 用于记录字典树中节点的数量。二维数组 \(tree\) 表示字典树的结构,其中 \(tree[i][j]\) 表示第 \(i\) 个节点的第 \(j\) 个子节点。

\(\mathcal{子功能实现}\)

\(\mathcal{insert}\)

实现一个 \(insert\) 函数,用于向字典树中插入一个字符串。它遍历字符串中的每个字符,将字符转换为数组下标(通过减去' \(a\) '并加上 \(1\) )。如果当前字符对应的子节点不存在,则创建一个新的节点并更新节点计数器。最后,在字符串末尾的节点中,更新字符串出现的次数。

\(\mathcal{query}\)

实现一个 \(query\) 函数,用于查询字典树中字符串的出现次数。它遍历字符串中的每个字符,将字符转换为数组下标。如果当前字符对应的子节点不存在,说明字符串不存在,查询结束。否则,将指针移动到子节点。最后,返回字符串末尾节点对应的出现次数。

\(\mathcal{主程序逻辑}\)

读取操作数量 \(n\) ,然后循环处理每个操作。对于每个操作,读取操作类型( \(ope\) )和操作字符串( \(str\) )。如果操作类型为 "\(i\)" ,调用 \(insert\) 函数插入字符串;如果操作类型为其他(例如查询操作),调用 \(query\) 函数查询字符串,并输出查询结果。

\(\mathcal{模板代码实现}\)

#include <iostream>
using namespace std;
const int N = 1e+6 + 10;
int n, flag = 1;
string ope, str;
int tree[N][27], vis[N][27];
void insert(string str)
{
int pos = 0;
int tmp = 0;
for (int i = 0; i < str.size(); i++)
{
tmp = str[i] - 'a' + 1;
if (tree[pos][tmp] == 0) tree[pos][tmp] = flag ++;
pos = tree[pos][tmp];
}
vis[pos][tmp] ++;
}
int query(string str)
{
int pos = 0;
int tmp = 0;
for (int i = 0; i < str.size(); i++)
{
tmp = str[i] - 'a' + 1;
if (tree[pos][tmp] == 0) break;
pos = tree[pos][tmp];
}
return vis[pos][tmp];
}
int main()
{
cin >> n;
while (n--)
{
cin >> ope >> str;
if (ope == "i") insert(str);
else cout << query(str) << endl;
}
return 0;
}

字符串算法--$\mathcal{KMP,Trie}$树的更多相关文章

  1. 数据结构学习之字符串匹配算法(BF||KMP)

    数据结构学习之字符串匹配算法(BF||KMP) 0x1 实验目的 ​ 通过实验深入了解字符串常用的匹配算法(BF暴力匹配.KMP.优化KMP算法)思想. 0x2 实验要求 ​ 编写出BF暴力匹配.KM ...

  2. 字符串匹配算法之 kmp算法 (python版)

    字符串匹配算法之 kmp算法 (python版) 1.什么是KMP算法 KMP是三位大牛:D.E.Knuth.J.H.MorriT和V.R.Pratt同时发现的.其中第一位就是<计算机程序设计艺 ...

  3. 【LOJ#2507】[CEOI2011]Matching(KMP,树状数组)

    [LOJ#2507][CEOI2011]Matching(KMP,树状数组) 题面 LOJ 题解 发现要做的是排名串的匹配. 然后我们考虑把它转成这个位置之前有多少个数小于当前这个数,这样子只要每个位 ...

  4. [BZOJ 1535] [Luogu 3426]SZA-Template (KMP+fail树+双向链表)

    [BZOJ 1535] [Luogu 3426]SZA-Template (KMP+fail树+双向链表) 题面 Byteasar 想在墙上涂一段很长的字符,他为了做这件事从字符的前面一段中截取了一段 ...

  5. bzoj5130 字符串的周期(kmp,最小表示法)

    bzoj5130 字符串的周期(kmp,最小表示法) bzoj 题解时间 m很大,n很小. 周期很容易求,就是kmp之后n-fail[n]. 之后对于枚举所有的字符串用最小表示法,暴力搜索. 能过就完 ...

  6. Java数据结构之字符串模式匹配算法---KMP算法2

    直接接上篇上代码: //KMP算法 public class KMP { // 获取next数组的方法,根据给定的字符串求 public static int[] getNext(String sub ...

  7. Java数据结构之字符串模式匹配算法---KMP算法

    本文主要的思路都是参考http://kb.cnblogs.com/page/176818/ 如有冒犯请告知,多谢. 一.KMP算法 KMP算法可以在O(n+m)的时间数量级上完成串的模式匹配操作,其基 ...

  8. 字符串处理:kmp算法

    刷vj的时候遇到一个kmp算法,就学习了一下 看了某位大神的清楚解释略有领会 看了一遍之后,可以清楚的知道 void kmp 的模拟过程,就是j指针的运动情况 但是j指针的运动是如何具体的实现,这其实 ...

  9. 字符串匹配算法之————KMP算法

    上一篇中讲到暴力法字符串匹配算法,但是暴力法明显存在这样一个问题:一次只移动一个字符.但实际上,针对不同的匹配情况,每次移动的间隔可以更大,没有必要每次只是移动一位: 关于KMP算法的描述,推荐一篇博 ...

  10. 字符串匹配算法之kmp算法

    kmp算法是一种效率非常高的字符串匹配算法,是由Knuth,Morris,Pratt共同提出的模式匹配算法,所以简称KMP算法 算法思想 在一个字符串中查找另一个字符串时,会遇到如下图的情况 我们通常 ...

随机推荐

  1. 关于Java字符串、字符与数字之间的相互转换

    一.数字转字符串 //将整个数字转化为字符串 int i=456; //方法一 String str1=Integer.toString(i); System.out.println(str1); / ...

  2. 基于CFSSL工具创建CA证书

    背景描述 CA(Certification Authority)证书,指的是权威机构给我们颁发的证书. 在局域网中部署组件时,想要通过证书来实现身份的认证,确保通信的安全性,可以通过cfssl工具来进 ...

  3. bquote

    在Linux环境下,按"·"(1左边的按钮)会进入bquote模式 退出方法 按 Ctrl + C 其它(待补充)

  4. C 语言 数制

    C 语言 数制 数制也称计数制,是指用一组固定的符号和统一的规则来表示数值的方法.计算机处理的信息必须转换成二进制形式数据后才能进行存储和传输.计算机中,经常使用的进制有二进制.八进制.十进制.十六进 ...

  5. Cortex-M内核指令WFI和WFI

    背景 今天阅读Nordic SDK里的example时发现里面功耗管理使用的power_manage()函数主要就是调用了一个__WFE()函数.查阅资料了解到WFE是一条汇编指令,它可以让CPU内核 ...

  6. JAVA 、Http协议:

    JAVA如何配置服务器: Http协议: 1.什么是Http协议 HTTP,超文本传输协议(HyperText Transfer Protocol)是互联网上应用最为广泛的   一种网络协议.所有的W ...

  7. FileLocator Pro注册机

  8. ddddd

    项目二阶段总结 账户微服务 短信发送 1.压测发现问题 首先对短信smscomponent的send方法在test单元测试类中测试,不是真的发短信测试,可以建立请求开始和结束的时间戳来确定请求的耗时. ...

  9. 【git报错】hint: Updates were rejected because the tip of your current branch is behind

    有时候作为非master权限的项目参与者 在push的时候会遇到这样的报错: hint: Updates were rejected because the tip of your current b ...

  10. 关于 layui 弹出一个 DOM 表单的问题

    案例: 假设用  layer.msg 去弹出一个dom表单: 由官方文档可知,应该定义一个div,设置其 id 为某个值,然后写在 content 中: layer弹层组件开发文档 - Layui 但 ...