2024年尽量每日一题

本文解析了AcWing题库中的多种算法问题,涉及栈与双指针操作、运算符优先级判断、单调栈、滑动窗口、KMP字符串匹配、Trie树应用、最大异或对、并查集、连通块分析、堆排序、模拟堆等,以及迷宫问题和树的层次计算,展示了在实际编程中的技术应用和解题策略。
摘要由CSDN通过智能技术生成

AcWing 3302. 表达式求值 - AcWing

该题是双指针算法与栈的应用,通过遍历一次原始字符串即可完成计算

首先创立两个栈,一个存数字,一个存符号,还要创立一个无向图存储符号的优先级

计算函数:取数字栈顶的两个数,再取符号栈顶的一个符号,根据符号来对这两个数进行计算。

遍历一次原始数组,if判断四种情况

s[i]是数字:计算这个数字串的值 x = x * 10 + s[i] - '0',再将其压入nums栈内

s[i]是左括号:直接加入符号op栈内

s[i]是右括号:遇到右括号说明必定存在左括号与其对应,我们需要先计算括号里的内容,因此这时候开始对符号进行出栈操作,直到符号栈的top是左括号为止

s[i]是符号:如果符号栈顶的符号优先级大于当前s[i]的符号,先计算s[i]之前的内容,直到栈顶的符号优先级小于当前s[i]的符号,将该符号直接进栈。如果符号栈已清空,则直接将s[i]入栈

最后计算剩下符号,将符号数组清空

详细解析:AcWing 3302. 表达式求值:多图讲解运算符优先级+详细代码注释 - AcWing

830. 单调栈 - AcWing题库

单调栈

这道题比较简单,没啥好说的,要点在于进栈和出栈的判断,当即将入栈的数大于栈顶元素,则直接入栈,即将入栈元素小于的话就while循环直到不小于栈顶元素,或者将栈清空。

此时栈顶元素就是左侧第一个小于的数。

y总说这个基本用不到,但是还是学一下。

AcWing 830. 单调栈--图解,详细注释 - AcWing

154. 滑动窗口 - AcWing题库

单调队列

用暴力应该会超时,但是我没试过。

这道题的关键在于要知道滑动窗口内两个数的关系:

以取滑动窗口最大值为例:滑动窗口内假设两个数分别为a和b,a在b的左边,即a下标小于b下标,但是b的值大于a的值,这时会发现,a永远都不可能是最大值。

以此为基础,我们新建一个队列,从下标为0开始从小到大遍历数组里面的每一个数,其中分为四种操作

1.while循环队列:当队列不为空且即将入队列的数大于队尾时,我们将队尾推出。

2.while循环结束后我们将即将入队的元素推入队尾

3.判断此时的队首是否滑出窗口:可以根据遍历数i与滑动窗口长度k来判断(这里i初始为0和1会有区别),利用i-k的关系来判断当前的窗口长度是否已经大于k,并且如果队首值恰好是滑出窗口的数,则将队首推出

4.判断是否已经形成窗口:如果形成窗口,则输出最大值

个人理解比较难的是下标和窗口的长度之间的关系,即为第三步,我们要清楚因为遍历是从小到大的,所以下标必定是将要入队列的数会大于已经入队列的数,这时就满足了滑动窗口两个数的关系的其中一个,第二个就需要我们判断了:是否即将入队列的数会大于/小于队尾的元素,如果是,则可以完全删除队尾的元素。

AcWing 154. 滑动窗口---海绵宝宝来喽 - AcWing

831. KMP字符串 - AcWing题库

KMP对于我来说太难了,早上看了两个小时只是略懂,好多不是很懂的,不瞎说了

AcWing 831. KMP字符串 - AcWing

835. Trie字符串统计 - AcWing题库

trie字符串统计,我觉得主要是两个问题,1:记录一个字符串有哪些字符。2:记录这个字符串出现的次数

1:如何记录一个字符串存在哪些字符?首先我们要明确在字符串的字符有哪些信息:下标和字母,我们需要根据下标和字符来精准的确定字符的唯一性,所以我们开辟一个二维数组t[N][26],N的意思是下标,26的意思是二十六个字母。因为下标的长度是1e5,所以是N,而字母只有26个,我们开27个也无伤大雅(算上0)。

2:如何记录这个字符串出现的次数?这就是trie数组我觉得最难的地方,trie数组是一个跟树一样的数组,它根据前一个点的值推出下一个点的信息。对于这道模板题,我们可以新开一个变量idx来进行承上启下的工作,idx是全局变量,对于idx的每次改变都是全局性的,在input函数中,我们用它赋给新点值,并把他的值作为p的下一个值(p是二维数组t的第一个参数,起到下标的作用),其实简而言之idx就是下标值,我们给每个input的字符串的每个字母赋予的下标值。最后我们cnt数组直接记录最后一个字符的下标idx出现的次数即可

我觉得我说的有点乱,但是意思就是那个意思,不如看小黄人的解析

AcWing 835. Trie树图文详解 - AcWing

昨天打训练赛去了

143. 最大异或对 - AcWing题库

这个是trie数组的例题

写了一遍,再细想一下,之前对于trie数组的理解挺多不正确的,带入了几个例子去看的话会清晰很多,所以很多时候代入法会更好理解。

上次对于idx的理解还不够深,idx是下标,每一个值对应的idx都是不同的,以上次那找集合的题为例,ab和ba,他们idx是不同的,但是abc和ab,他们的ab是相同的。

回归到这个最大异或对,首先数据范围是2^31次方,用int可以解决;其次代码其实和上一题的代码很像,思路不一样而已,这个是求最大值。

insert函数:插入函数,输入一个数,然后对于每一个位在trie数组中赋值,for循环要从30开始,因为我们后续求值是一直乘以二嵌套的。其他和上一题的insert一样

search函数:寻找最大值,对于我们输入的每一个数,都去匹配看看是否存在另一个数,使其成为异或对的最大值。由于我们是按照位数来进行计算的,所以我们要用一个sum变量来记录最后的整数值,根据输入的数x的各个位,我们根据trie数组寻找,如果这个位的否存在(!x),则可以对sum进行加一处理,并且将下标指针指向这个否值的下一个数,即为p=t[p][!x]。如果这个位不存在,则不对sum加一,并且将下标指针指向这个值的下一个数,即为p=t[p][x]。

我觉得比较关键的几点:第一因为是从30开始的,所以先匹配到的永远比后匹配到的优先级高。第二,每个t值如果存在,则其必存在前驱结点。

AcWing 143. 最大异或对---Trie详解 - AcWing

836. 合并集合 - AcWing题库

并查集,模板题的话还是简单的

每个数最开始都是一个集合,赋值为1,如果需要把集合并起来,则把他们的根节点合并,根节点集合为p。主要问题就在于如何寻找根节点,构造函数find(int x)实现,寻找根节点时,只要根节点的值与下标不一样,则证明不是根节点,需要进行迭代寻找。

需要注意的就是这个迭代了,我第一次使用return直接返回find(p【x】),发现这么做会超时,但是使用p【x】=find(p【x】)就不会了。其实这两种写法最终效果是一样的,区别在于一个赋值给了p【x】,一个没赋值。直接return的时候,相当于一直寻找父亲结点,父亲的父亲结点等等,一直找到目标x = p【x】,但是如果数据庞大的时候,每一次寻找都要耗费许多时间。使用赋值的方法时,每个结点都被赋值为根节点的值,这样就可以省下很多时间了。

AcWing 836. 合并集合--海绵宝宝来喽 - AcWing

837. 连通块中点的数量 - AcWing题库

这题和模板题一模一样,就是多了个求集合内结点的数量。在初始化时除了给每个结点的p值赋x外,再新建一个求集合结点数量的数组sum,初始值都为1,因为都只有一个点。如果输入的a点和b点并没有在同一个集合内,那么在合并集合的时候还需要将集合中的点的数量合并,即sum[find(b)] += sum[find(a)] (这里的顺序可以改变,取决于合并集合时是find(a)赋值给find(b)或者find(b)赋值给find(a),这里是后者)。

AcWing 837. 连通块中点的数量 - AcWing

838. 堆排序 - AcWing题库

堆排序分为三步,第一找出大顶堆或小顶堆,这里是找出小顶堆,第二完成后把最小值与最大值交换(就是小顶堆的根节点与末尾结点),第三将边界-1进行递归,直到所有数排序完成

AcWing 838. 堆排序--海绵宝宝来喽 - AcWing

839. 模拟堆 - AcWing题库

这个也是堆排序,例题,但是比较难,它需要修改任意下标的数,修改交换位置时就不仅仅是修改值了,还得修改地址,进而保持第K个数中的K值准确无误,其他的up和down操作与堆排序一样。

AcWing 839. 如何理解模拟堆中的heap_swap,hp[N], ph[N]? - AcWing

842. 排列数字 - AcWing题库

dfs算法的例题,深度优先。本质就是插空,在每一个空位都尝试插入新的数字,并且要保证不重复,这点使用一个bool数组进行解决,插空使用dfs进行递归解决。

例题比较简单

843. n-皇后问题 - AcWing题库

n皇后问题是典型的dfs问题,思路是比较简单的,但是实现起来有点难。在棋盘上,我们一一遍历每个位置,尝试在这些位置上放置皇后,并且判断是否符合条件,如果符合条件,那么就更改棋盘,也就是放置皇后,如果不符合,那么就这个位置上的皇后拿掉,并且还原现场。当然,这里可能会有个疑问?这样子能否遍历出所有合适的情况?答案当然是可以的,因为如果该位置符合条件,那么我们在更改棋盘并且完成递归后,也会进行一次将该位置上的皇后拿掉的操作,所以每一个位置都进行了两种情况的遍历。总而言之,对于棋盘上的某个位置来说,有两种情况:一,不符合放置条件,ok,跳过这个位置直接进行下一个位置的询问。二,符合放置条件,那么就放置皇后,对条件加以这个位置的限制,然后再进行递归,进行下一个位置在这个位置放置皇后的条件下的询问,最后的最后,递归回这个位置后,对于这个位置进行还原现场,即还原为不放置皇后的情况,这里就和第一种情况一样了。因此,dfs可以遍历所有的放置情况,一个不漏。

限制条件是同一行、同一列或同一斜线不能有两个皇后,我是用对角线与一行来进行限制。我们需要做个映射,每一条对角线与每一行需要对应一个数,行较为直观简单,直接就是x,对角线根据坐标系来求,分别为x + i与 i - x + n。在数学上这两条线对于不同的x为不同的值,符合我们的要求。

Ubuntu Pastebin 这是我的代码

844. 走迷宫 - AcWing题库

BFS的模板题,朴素的思路我感觉挺暴力的:在每一个点上,向上下左右四个方向询问是否可以前进,如果可以则将这个点的ans值设为前一个ans值加一(ans指的是从起点到x,y这个点的最小值),如果不可以则进行下一步,然后重复这个步骤,最后的答案就是ans【n】【m】(n,m是目标的点)。

实现:需要创建一个地图的数组,地图数组是无法改变的,再建立一个答案数组ans,用来存储到某个点的最小值,还需要一个队列,存放坐标值,因为坐标值有x,y两个值,所以使用pair容器。初始化时,需要注意将ans数组全体设置为-1(也可以是其他值,但是最好小于零),表示在广度优先搜索时未经过,因为初次经过一个点时,步数肯定是最小的,第二次经过时,步数必然比第一次经过大,这是广度优先搜索特性决定的。实现的关键点在于队列与询问条件,终止搜索的要求是队列为空,即无法找到下一个符合条件的点了,因为如果存在符合条件的点,那么就会入队列。询问条件为:是否越过地图边界,ans数组是否不为-1,地图是否允许经过该点。

这是我的代码 Ubuntu Pastebin

专业题解 AcWing 844. 走迷宫:图解+代码注释 - AcWing

845. 八数码 - AcWing题库

挺像例题的,思路好想出来但是挺难实现

AcWing 845. 八数码--详细图解 - AcWing

3/12 1343. 挤牛奶 - AcWing题库

需要用到区间合并,如果熟悉pair会好写点

3/14 846. 树的重心 - AcWing题库

树的DFS,需要用到邻接表,将每个树的结点都做成一个头结点,从而形成邻接表

邻接表的基本操作:add和遍历

添加就是普通的存在头指针的模拟链表插入操作,注意这里的头指针不存在值,只是一个指向作用。遍历使用dfs进行,也是模拟链表的遍历操作,i = h【x】(头指针);i;i = ne【i】进行迭代。

剩下的工作就是对数据进行存储和利用了,我们需要记录某个结点被删除后剩余结点的总数量sum,我们还要记录最大的剩余子树的节点数res。在dfs迭代之后,将res与n-sum进行比较,最后就是答案。

Ubuntu Pastebin

3/16 847. 图中点的层次 - AcWing题库

有向图的bfs,邻接表+bfs的队列模版

从一号结点开始遍历,使用dist数组记录每个点距离一号结点的距离,过程中每个结点仅遍历一次,否则会造成重复。

AcWing 847. 图中点的层次--广度优先遍历详解 - AcWing

  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值