基础算法篇(4)(蓝桥杯常考点)—数据结构(进阶)

基础算法篇(4)(蓝桥杯常考点)—数据结构(进阶)

前言

这期将会讲到基础算法篇里面的数据结构(进阶),主要包括单调栈,单调队列,并查集,扩展域并查集,带权并查集,字符串哈希,Trie树。

数据结构(进阶)正文

单调栈

里面存储的单增或者单减的栈

应用:

1.寻找当前元素左侧,离它最近,并且比它大的元素在哪

2.寻找当前元素左侧,离它最近,并且比它小的元素在哪

3.寻找当前元素右侧,离它最近,并且比它大的元素在哪

4.寻找当前元素右侧,离它最近,并且比它小的元素在哪
寻找当前元素左侧,离它最近,并且比它大的元素在哪 int a[N]里面存数(已存好) ret里面存的答案 stack<int>st;//维护一个单调递减的栈,里面存的是下标 for(int i = 1;i<=n;i++) { //栈里面小于等于a[i]的元素全部出栈 while(st.size()&&a[st.top()]<=a[i]) st.pop(); //此时栈顶元素存在,栈顶元素就是所求结果 if(st.size()) ret[i]=st.top(); st.push(i); } 寻找当前元素右侧,离它最近,并且比它大的元素在哪 改成for(int i = n;i>=1;i--) 
寻找当前元素左侧,离它最近,并且比它小的元素在哪 int a[N]里面存数(已存好) ret里面存的答案 stack<int>st;//维护一个单调递增的栈,里面存的是下标 for(i=1;i<=n;i++) { //栈里面大于等于a[i]的元素全部出栈 while(st.size()&&a[st.top()]>=a[i])st.pop();//这里的符号是跟上面的唯一区别 //此时栈顶元素存在,栈顶元素就是所求结果 if(st.size()) ret[i]=st.top(); st.push(i); } 寻找当前元素右侧,离它最近,并且比它小的元素在哪 把上面改为for(int i=n;i>=1;i--)即可//n次逆遍历可以记一下是这个 
总结: 找左侧,正遍历;找右侧,逆遍历; 比它大,单调减;比它小,单调增。//构造___栈 例题: 洛谷 P1901 发射站 

洛谷 P1901 发射站

单调队列

是一个存单调元素的双端队列

应用:解决滑动窗口内的最大值最小值问题

(前面基础算法的滑动窗口不是用来求其中的最值的)

洛谷 P1886 滑动窗⼝ /【模板】单调队列

例题:洛谷 P1886 滑动窗⼝ /【模板】单调队列 int a[N]里面存的元素(已存好) 窗口内最大值: 从左往右遍历元素,维护一个单调递减的双端队列 当前元素进队之后,注意维护队列内的元素在大小为k的窗口内 此时队头元素就是最大值 代码: deque<int>q;//存下标 for(int i = 1;i<=n;i++) { while(q.size()&&a[q.back()]<=a[i])q.pop_back(); q.push_back(i); if(q.back()-q.front()+1>k) q.pop_front(); if(i>=k)cout<<a[q.front()]<<" "; } 窗口内最小值: 从左往右遍历元素,维护一个单调递增的双端队列 当前元素进队之后,注意维护队列的元素在大小为k的窗口内 此时队头元素就是最小值 

并查集

并查集是一种用于维护元素所属集合的数据结构,用双亲表示法来实现

应用eg:维护连通块的信息

相关的一些概念:

查询操作:查找元素x属于哪一个集合,一般会在每个集合中选取一个元素作为代码,查询的是这个集合中的代表元素

合并操作:将元素x所在的集合与元素y所在的集合合并成一个元素

(注意:合并的是元素所属的集合,而并非单单两个元素)

判断操作:判断元素x和y是否在同一个集合

洛谷 P1551 亲戚

并查集的实现: 例题:洛谷 P1551 亲戚 1.初始化:让元素自己指向自己即可 int fa[N];一般并查集用fa来表示 for(int i=1;i<=n;i++) fa[i] = i; 2.查询操作:就是一直向上"找爸爸"(这个find可以多次使用) int find(int x)//查询x所在集合的代表元素是谁 return fa[x] == x?x:find(fa[x]);//是x就返回x,不是就find(fa[x]) 3.合并操作:(重复合并不会出错) 让元素x所在集合的代表元素指向元素y所在集合的代表元素 void un(int x,int y) { int fx = find(x); int fy = find(y); fa[fx] = fy; } 4.判断操作 看看两者所在集合的总代表元素是否相同 bool issame(int x,int y) { return find(x) == find(y); } 

扩展域并查集

元素之间存在多种关系比如:朋友和敌人 而不像上面只存在:亲戚这样一种关系的话,就要用扩展域并查集

和普通并查集的区别:将每个元素拆分成多个域,每个域代表⼀种状态或者关系

洛谷 P1892 [BOI2003] 团伙

例题:洛谷 P1892 [BOI2003] 团伙 这里只写不同点: find和un与上面的写法一模一样 //两种关系,所以N*2:x的母敌人是x+n int fa[N*2]; //初始化: for(int i=1;i<=n*2;i++) fa[i]=i; while(m--)//m是题目中的"m个关系" { if(op == 'F') un(x,y); else//敌人,读取的是y和x是敌人关系 {//存法:这俩都得写,少一个都不行 un(x,y+n);//这两是朋友关系 un(y,x+n);//这两是朋友关系 } } 

带权并查集

概念:就是在普通并查集的基础上,为每个结点增加一个权值。这个权值可以表示当前结点与父结点之间的信息(因为find那我们用的路径压缩,因为最终这个权值是当前结点相对于根节点的信息)

洛谷 P1196 [NOI2002] 银河英雄传说

带权并查集的一些操作:(这里的d[N]以到父结点的距离为例) 例题:洛谷 P1196 [NOI2002] 银河英雄传说 新加了一个d[N] 1.初始化: 多初始化个d[i]即可 2.查询操作:(对这种代码来说,一个结点只能进行一次这种find操作!) int find(int x) { if(fa[x]==x) return x; int t = find(fa[x]);//这一步要先搞 d[x]+=d[fa[x]];//不为距离时可能会变为其他 return fa[x] = t;//完成路径压缩 } 3.合并操作://x所在集合与y所在集合合并,x与y之间的权值是w void un (int x,int y, int w) { int fx = find(x),fy = find(y); if(fx!=fy) { fa[fx] = fy; d[fx]= d[y]+w-d[x]; //可能会变,这里是拿距离举例的 } } 4.查询操作://查询y与x之间的距离 int query(int x,int y) { int fx = find(x),fy = find(y); //如果不在同一个集合中,说明距离未知(具体返回什么要看题意) if(fx!=fy)return 0x3f3f3f3f; return d[y]-d[x]; } 

字符串哈希

一般利用前缀和思想去预处理字符串汇总每个前缀的哈希值

(使用前提:需要多次询问一个字符串的子串的哈希值)

核心思想:把字符串映射成P进制数字

P一般选择13331或者131

字符串哈希的作用:

字符串哈希一般用于判断两个字符串及其各子串是否相等

(和字典树的区别是这个字符串哈希侧重于判断功能)

洛谷 P10468 兔⼦与兔⼦

例题:洛谷 P10468 兔⼦与兔⼦ 前缀字符串哈希模板: typedef unsigned lon long ULL; P = 13331; int len; string s;//一般都要搞一下s = ' '+s;来让i从1开始搞 ULL f[N];//前缀哈希数组 ULL p[N];//记录P的i次方->p[i]为P的i次方 //处理前缀哈希数组以及P的i次方数组 void init_hash() { f[0] = 0;p[0] = 1; for(int i = 1;i<=len;i++) { f[i]=f[i-1]*P+s[i]; p[i]=p[i-1]*P; } } //快速求得任意区间的哈希值 ULL get_hash(int l,int r) { return f[r]-f[l-1]*p[r-l+1]; } 如果题目只是简单的求单个字符串的哈希值: ULL gethash() { ULL ret = 0; for(int i =1;i<=len;i++) { ret = ret*p+s[i]; } return ret; } 

Trie树(又叫字典树或前缀树)

是一种能够快速插入和查询字符串的数据结构

理解:我们可以把字典树想象成一颗多叉树,每一条边代表一个字符,从根节点到某个节点的路径就代表了一个字符串

作用:

1.查询某个单词是否出现过,并且出现几次

2.查询有多少个单词是以某个字符串为前缀

3.查询所有以某个前缀开头的单词
字典树的实现: 默认需要存的全是小写字母 1.准备工作 int tree[N][26],p[N],e[N];//N一般令为所有字符串中一共有多少个字符 // p[i]表示第i个被开辟的点被经过了多少次, //e[i]表示以第i个被开辟的点为结尾的有多少个 int idx; 2.插入字符串 void insert(string&s) { int cur = 0;//从根节点开始 p[cur]++;//这个格子经过一次 for(auto ch:s) { //这个path的表达式常改!!!依据题意改 int path = ch - 'a'; //如果没有路 if(tree[cur][path] == 0) tree[cur][path]= ++idx; cur = tree[cur][path]; p[cur]++ } e[cur]++; } 3.查询字符串出现的次数: int find(string&s) { int cur = 0; for(auto ch:s) { int path = ch - 'a'; if(tree[cur][path] == 0) return 0; cur = tree[cur][path]; } return e[cur]; } 4.查询有多少个单词以字符串s为前缀: int find_pre(string&s) { int cur = 0; for(auto ch:s) { int path = ch-'a'; if(tree[cur][path] == 0) return 0; cur = tree[cur][path]; } return p[cur]; } 例题:洛谷 P2580 于是他错误的点名开始了 

洛谷 P2580 于是他错误的点名开始了

Read more

“现在的AI就像1880年的笨重工厂!”微软CSO斯坦福泼冷水:别急着造神

“现在的AI就像1880年的笨重工厂!”微软CSO斯坦福泼冷水:别急着造神

大模型仍未对上商业的齿轮? 编译 | 王启隆 来源 | youtu.be/aWqfH0aSGKI 出品丨AI 科技大本营(ID:rgznai100) 现在的硅谷,空气里都飘着一股“再不上车就晚了”的焦躁感。 最近 OpenClaw 风头正旺,强势登顶 GitHub,终结了 React 神话,许多人更是觉得“AI 自己干活赚钱”的日子就在明天了。 特别是在斯坦福商学院(GSB)这种地方,台下坐着的都是成天琢磨怎么用下一个技术风口搞个独角兽出来的狠人。 微软的首席科学官(CSO)Eric Horvitz 被请到了这个几乎全美最想用 AI 变现的礼堂里。作为从上世纪 80 年代就开始搞 AI 的绝对老炮、也是微软技术底座的“扫地僧”,这位老哥并没有顺着台下的胃口,去吹捧下个月大模型又要颠覆什么行业,而是兜头给大家浇了一盆带点学术味的冷水。 他讲了一个挺有画面感的比喻:大家都在聊

By Ne0inhk
Godot被AI代码“围攻”!维护者崩溃发声:“不知道还能坚持多久”

Godot被AI代码“围攻”!维护者崩溃发声:“不知道还能坚持多久”

整理 | 郑丽媛 出品 | ZEEKLOG(ID:ZEEKLOGnews) 当大模型能在几秒钟内生成一段“看起来像那么回事”的补丁时,开源社区却开始付出另一种代价。 最近,开源游戏引擎 Godot 的核心维护团队公开吐槽:他们正被大量“AI 生成的低质量代码”淹没。那些代码往往结构完整、注释齐全、描述洋洋洒洒,但真正的问题是——提交者可能并不理解自己交上来的内容。 这件事,并不是简单的“有人偷懒用 AI 写代码”。它正在触及开源协作最核心的东西:信任。 一场悄无声息的“AI 洪水” 事情的导火索来自一条 Bluesky 讨论帖。 Godot 主要维护者之一、同时也是 Godot 商业支持公司 W4 Games 联合创始人的 Rémi Verschelde 表示,所谓的“AI slop”

By Ne0inhk
诺奖得主辛顿最新访谈:1 万个 AI 可以瞬间共享同一份“灵魂”,这就是为什么人类注定被超越

诺奖得主辛顿最新访谈:1 万个 AI 可以瞬间共享同一份“灵魂”,这就是为什么人类注定被超越

当宇宙级的“嘴炮”遇到降维打击。 编译 | 王启隆 来源 | youtu.be/l6ZcFa8pybE 出品丨AI 科技大本营(ID:rgznai100) 打开最新一期知名播客 StarTalk 的 YouTube 评论区,最高赞的一条留言是这样写的: “我长这么大,第一次看到尼尔·德葛司·泰森(Neil deGrasse Tyson)在一档节目里几乎全程闭嘴,像个手足无措的小学生一样乖乖听讲。” 作为全美最知名的天体物理学家,泰森平时的画风是充满激情、喋喋不休、用宇宙的宏大来震撼嘉宾。但这一次,坐在他对面的那位满头银发、带着温和英音的英国老人,仅仅用最平淡的语气,就让整个演播室陷入了数次令人窒息的沉默。 这位老人是 Geoffrey Hinton。深度学习三巨头之一,2024 年诺贝尔物理学奖得主,被公认为“AI 教父”。 对经常阅读 Hinton 演讲的我来说,这也是比较新奇的一幕—

By Ne0inhk
48小时“烧光”56万!三人创业团队濒临破产,仅因Gemini API密钥被盗:“AI账单远超我们的银行余额”

48小时“烧光”56万!三人创业团队濒临破产,仅因Gemini API密钥被盗:“AI账单远超我们的银行余额”

整理 | 苏宓 出品 | ZEEKLOG(ID:ZEEKLOGnews) 「仅过了 48 小时,一笔 8.2 万美元的天价费用凭空出现,较这家小型初创公司的正常月费暴涨近 46000%。」 这不是假设的虚幻故事,而是一家墨西哥初创公司正在经历的真实危机。 近日,一位名为 RatonVaquero 的开发者在 Reddit 发帖求助称,由于他的 Gemini API 密钥被盗用,原本每月仅约 180 美元(约 1242 元)的费用,在短短 48 小时内暴涨到 82,314.44 美元(约 56.8 万元)。对于这家只有三名开发者的小型创业团队来说,这笔突如其来的账单,几乎等同于灭顶之灾。 “我现在整个人都处在震惊和恐慌之中。”RatonVaquero

By Ne0inhk