数据结构:kmp算法,Trie树,以及并查集的干货详解---小白也能看懂

数据结构:kmp算法,Trie树,以及并查集的干货详解---小白也能看懂
  

🎬 博主名称个人主页

🔥 个人专栏《算法通关》《Java讲解》

⛺️心简单,世界就简单
序言

昨晚数据结构写了一半,做图太累了,文章写的比较慢,这篇应该就是第二篇,后面还有一篇,太困了,真不行了

今天讲一下 kmp算法,Trie, 并查集

目录

序言

KMP算法

原理

next数组

匹配过程

Trie树

并查集


KMP算法

这里说一下kmp的大致情况

用于处理字符串匹配问题,他也是十分的抽象                给一个S[]主串(比较长的那个),P[]为模板串,kmp我们一般用下标1来开始遍历

接下来我们需要去思考的是

1,暴力去怎么做

2,怎么去优化

下面是暴力的模板代码

大概意思就是,每当我们匹配到不一样的部位,我们的P就要从头开始再跟刚刚s的起点+1位置重新匹配,        这样就会造成串的长度很长时候,就会超时,所以我们就要从这个过程中找性质了

 for(int i = 1; i <= m; i ++){//枚举当前的起点 bool flag = true;// 成功的状态 for(int j = 1; j <= n; j++){ if(S[i+j-1] != P[j]){ flag = false; break; } } }
原理

看这个第一个是暴力,我们需要每次遇到不一样的字符,就让P从头开始,去匹配 S 串,这样我们其实可以发现 P 串他本身就会有一些相同的前缀 后缀,然后当我们遇到不相同的字符,我们没必要再一个一个匹配,我们可以直接跳到一定位置接着继续匹配,这就是我们的原理

现在我们就要去思考,我们怎样找到,当一个位置匹配失败时,我们需要让这个串最多移动多少,这就是我们常常听说的next数组的用处了


next数组

next[ i ] 的含义就是以 i 为终点的这个后缀 和 从1开始的这个前缀相等,且这个长度最长

比如, next[ i ] = j,意思就是,p[ 1.....j] = p[ i - j + 1........i]

next数组咱咋求,我们先假设 i-1 位置(包括i-1这个位置)之前的最长的前缀 和 后缀的长度为 j ,如果此时 i 位置 和 j + 1位置相等,那我们就在此基础上先 j  ++,然后让ne[ i ] = j,如果就是位置不相等嘞,那我们就利用next[ j ]找到这个相等的前缀,然后继续匹配,也就是 j = ne[ j ]
好了大致就是这样,你一定要先知道next数组是干啥

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);//减n是因为,字符串的位置是从0开始 j = ne[j];//成功后可能后面还有能匹配的,继续操作 } }
 for(int i = 2, j = 0; i <= n;i ++){ while(j && P[i] != P[j + 1]) j = ne[j]; if(P[i] == P[j + 1]) j ++; ne[i] = j; }

匹配过程

我们先明确指针,大概就是上面这个图,我们每次是要看j + 1 和 i位置是否相同,不同就让j退回到ne[ j ]位置,然后再看j + 1位置和 i 是否相同,如果相同我们就让j ++,然后让ne[ i ] 等于j

代码其实和构造next数组几乎一样

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);//减n是因为,字符串的位置是从0开始 j = ne[j];//成功后可能后面还有能匹配的,继续操作 } }

合起来就是这个,下面是题目模板

#include<iostream> using namespace std; const int N = 1e4 + 10; const int M = 1e5 +10; char S[M], P[N], ne[N], n, m; int main(){ cin >> n >> (P + 1) >> m >> (S + 1); //求next过程 for(int i = 2, j = 0; i <= n;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);//减n是因为,字符串的位置是从0开始 j = ne[j];//成功后可能后面还有能匹配的,继续操作 } } } 

Trie树

用来快速的存储和查找字符串集合的数据结构

这个很简单我们来拿给题举例子

现在给了左侧这么多单词,我们来存进树里,我们从根节点开始,将每个单词的字母一一存进去,另外我们给最后一个字母做上标记,防止少走某些点

#include<iostream> using namespace std; const int N = 1e5 + 10; char str[N]; int son[N][26], cnt[N], idx;//下标是0的带你,既是根节点又是 空节点 //cnt是以当前这个点结尾的单词有多少个 //插入操作 void insert(char str[]){ int p = 0;//从根节点开始,从0开始遍历 for(int i = 0; str[i]; i ++){ int u = str[i] - 'a'; //如果p这个节点不存在u这个儿子,就创建一个 if(!son[p][u]) son[p][u] = ++idx; p = son[p][u]; } cnt[p]++; } //查询操作 int query(char str[]){ int p = 0; for(int i = 0; str[i]; i ++){ int u = str[i] - 'a'; if(!son[p][u]) return 0; p = son[p][u]; } return cnt[p]; } int main(){ int n; scanf("%d", &n); while(n --){ char op[2]; scanf("%s%s", op, str); if(op[0]=='I') insert(str); else printf("%d\n", query(str)); } } 

并查集

我们先知道并查集是干啥的

1,他是将两个集合合并

2,询问两个元素是否在一个集合中

基本原理 : 每个集合用一颗树来表示,树根的编号就是整个集合的编号,每个节点存储他的父节点,p[ x ]表示父节点

问题 1:如何判断树根:if(p[ x ] == x)

问题2 :如何求x的集合编号:while( p[ x ] !=x) x = p[ x ];

问题3: 如何合并两个集合:假设p[ x ]是x的集合编号,p[ y ] 是y的集合编号,直接让这两个其中一个插到集合根-------p[ find(x) ] = p[ u ]

优化:路径压缩

下面展示一下并查集模板

#include<iostream> using namespace std; const int N = 1e5 + 10; int p[N], n, m; int find(int x){ //返回下的祖宗节点,路径压缩优化 if(p[x] != x) p[x] = find(p[x]); return p[x]; } int main(){ cin>>n>>m; //最开始自己就是根 for(int i = 1; i <= n; i++) p[i] = i; while(m --){ char op[2]; int a, b; scanf("%s%d%d", op, &a, &b); if(op[0] == 'M') p[find(a)] = find(b); //合并操作让a的祖宗节点的父亲等于b的祖宗 else{ //判断两个节点是不是在一个集合 if(find(a)==find(b)) puts("Yes"); else{ puts("No") } } } }

如果说我们要求出每一个集合的有多少个点呢

这时候我们添加一个size数组就行了,如果合并就让 sizes[find(b)] += sizes[find(a)];

如果两个点在一个集合就 continue

#include<iostream> using namespace std; const int N = 1e5 + 10; int p[N], n, m, sizes[N]; int find(int x){ //返回下的祖宗节点,路径压缩优化 if(p[x] != x) p[x] = find(p[x]); return p[x]; } int main(){ cin>>n>>m; //最开始自己就是根 for(int i = 1; i <= n; i++) p[i] = i, sizes[i] = 1; while(m --){ char op[5]; int a, b; scanf("%s", op); if(op[0] == 'C') { scanf("%d%d", &a, &b); if(find(a) == find(b)) continue; sizes[find(b)] += sizes[find(a)]; p[find(a)] = find(b); } //合并操作让a的祖宗节点的父亲等于b的祖宗 else if(op[1] == '1'){ scanf("%d%d", &a, &b); //判断两个节点是不是在一个集合 if(find(a)==find(b)) puts("Yes"); else{ puts("No"); } } else { scanf("%d", &a); printf("%d\n", sizes[find(a)]); } } }

Read more

假网站排全网第二,真官网翻五页都找不到!NanoClaw创始人破防:SEO之战,我快要输了

假网站排全网第二,真官网翻五页都找不到!NanoClaw创始人破防:SEO之战,我快要输了

整理 | 苏宓 出品 | ZEEKLOG(ID:ZEEKLOGnews) 自从 OpenClaw 爆火之后,各种“Claw”项目接连出现,其中以安全优化版 NanoClaw 最为知名。它的核心代码仅有 4000 行,却获得了 AI 大牛 Andrej Karpathy 的点赞。 可谁也没想到,这款口碑极佳的开源项目,近来竟被一个仿冒网站抢了风头。 投诉无门之下,NanoClaw 创始人 Gavriel Cohen 在 X 社交平台上无奈发文怒斥:谷歌搜索错误地将假网站排在真官网前面,不仅破坏了项目声誉,还埋下了严重的安全隐患,而他费尽心力,却只能哀叹一句——“我正在为自己的开源项目打 SEO 战,但我快要输了。” 那么,NanoClaw 究竟发生了什么?又是怎么走红的?事情还要从 OpenClaw

By Ne0inhk
曝Windows 12将于今年发布?以AI为核心、NPU成「硬件门槛」,网友吐槽:“不想要的全塞进来了”

曝Windows 12将于今年发布?以AI为核心、NPU成「硬件门槛」,网友吐槽:“不想要的全塞进来了”

整理 | 郑丽媛 出品 | ZEEKLOG(ID:ZEEKLOGnews) 当年,微软一句“Windows 10 将是最后一个版本”的表态,让不少用户以为 Windows 进入了“只更新、不换代”的时代。但几年过去,现实却完全不同。 在 Windows 11 发布之后,如今关于 Windows 12 的传闻再次密集出现。从内部代号、代码片段,到硬件厂商的暗示与 OEM 预热标签,种种线索拼在一起,勾勒出一个明显的趋势——这不会只是一次常规升级,而更像是一次围绕 AI 的平台级重构。 更关键的是,这次争议,可能远比当年 TPM 2.0 更大。 精准卡位 Windows 10 退场的时间?

By Ne0inhk
Python热度下滑、AI能取代搜索引擎?TIOBE最新榜单揭晓!

Python热度下滑、AI能取代搜索引擎?TIOBE最新榜单揭晓!

整理 | 屠敏 出品 | ZEEKLOG(ID:ZEEKLOGnews) 日前,TIOBE 发布了最新的 3 月编程语言榜单。整体来看,本月排名变化不算大,但榜单中仍然出现了一些值得关注的小波动。  AI 工具能帮大家秒懂最新编程语言趋势? 由于 2 月天数较少,3 月的榜单整体变化有限。借着这次发布,TIOBE CEO Paul Jansen 也回应了一个最近被频繁讨论的问题:为什么 TIOBE 指数仍然依赖搜索引擎统计结果?在大语言模型流行的今天,直接询问 AI 哪些编程语言最流行,是不是更简单? 对此,Jansen 的回答是否定的。 他解释称,TIOBE 指数本质上统计的是互联网上关于某种编程语言的网页数量。而大语言模型的训练数据同样来自这些网页内容,因此从信息来源来看,两者并没有本质区别。换句话说,LLM 的判断,本质上也是建立在这些网页数据之上的。 Python 活跃度仍在下降

By Ne0inhk
“裸奔龙虾”数量已达27万只,业内人士警告;AI浪潮下,中传“砍掉”翻译等16个专业;薪资谈判破裂,三星电子8.9万人要罢工 | 极客头条

“裸奔龙虾”数量已达27万只,业内人士警告;AI浪潮下,中传“砍掉”翻译等16个专业;薪资谈判破裂,三星电子8.9万人要罢工 | 极客头条

「极客头条」—— 技术人员的新闻圈! ZEEKLOG 的读者朋友们好,「极客头条」来啦,快来看今天都有哪些值得我们技术人关注的重要新闻吧。(投稿或寻求报道:[email protected]) 整理 | 郑丽媛 出品 | ZEEKLOG(ID:ZEEKLOGnews) 一分钟速览新闻点! * “裸奔龙虾”已高达27万只!业内人士警告:一旦黑客入侵,敏感信息一秒搬空 * 阿里云 CTO 周靖人代管千问模型一号位,刘大一恒管理更多团队 * 中国传媒大学砍掉翻译、摄影等 16 个本科专业,直言教育要面向人机分工时代 * 雷军放话:小米将很快推出 L3、L4 的驾驶 * 消息称原理想汽车智驾一号位郎咸朋具身智能赛道创业 * vivo 前产品经理宋紫薇创业,瞄准 AI 时尚Agent,获亿元融资 * MiniMax 发布龙虾新技能,股价暴涨超 23% * 薪资谈判破裂,三星电子

By Ne0inhk