代码随想录算法训练营第十一天|150. 逆波兰表达式求值,239. 滑动窗口最大值,347.前 K 个高频元素,栈与队列总结

力扣题部分:

150. 逆波兰表达式求值

题目链接:. - 力扣(LeetCode)

题面:

给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。

请你计算该表达式。返回一个表示表达式值的整数。

注意:

  • 有效的算符为 '+''-''*' 和 '/' 。
  • 每个操作数(运算对象)都可以是一个整数或者另一个表达式。
  • 两个整数之间的除法总是 向零截断 。
  • 表达式中不含除零运算。
  • 输入是一个根据逆波兰表示法表示的算术表达式。
  • 答案及所有中间计算结果可以用 32 位 整数表示。

思路(栈):

        可能没见过的人一下子很难想出来,通过栈实现这个问题。

        遍历整个字符串数组,分两种情况:

        1.读到数字    做法:放进栈

        2.读到符号    做法:拿出栈里的两个元素进行对应符号操作后将结果放进栈。

        最后将栈顶弹出即可。

        需要注意的是:

        1.由于栈的先进后出原则,读到符号"-"或"/"的时候,先出来的数应该是减数或除数,后出来的是被减数和被除数。("+" 和 "*"由于交换律没有受影响)

        2.本题是在输入的结果合法的情况下,如果考虑不合法的话还需要很多判断条件。

代码实现:

239. 滑动窗口最大值

题目链接:. - 力扣(LeetCode)

题面:

        给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

返回 滑动窗口中的最大值 

示例 1:

输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
滑动窗口的位置                最大值
[1  3  -1] -3  5  3  6  7       3
 1 [3  -1  -3] 5  3  6  7       3
 1  3 [-1  -3  5] 3  6  7       5
 1  3  -1 [-3  5  3] 6  7       5
 1  3  -1  -3 [5  3  6] 7       6
 1  3  -1  -3  5 [3  6  7]      7

思路(单调队列):

        这个就更难想了。并且需要用到双端队列(deque)

        先说说什么是双端队列。这是一个同时具有栈和队列两个性质的结构,可以将两端的元素弹出或加入,本题解中主要是靠了队列两端都能靠pop拿出元素实现的。

        我们要在整个过程中保证队列单调递减。

        乍一看这句话有点天方夜谭:队列又不是有序的,滑动窗口内也不是有序的,这么保证的了单调递减?如果要排序一排完我们又不知道谁前谁后,到时候又要弹出谁怎么确定呢?

        先来思考一个问题。就拿这个示例1举例:如果num[1]的值(值为1)小于num[2](值为3),是不是就意味着不管后面值怎么排,num[1]都不会被轮到当最大值?

        好像确实如此 —— num[2]的值又大,位置又靠后,num[1]不就没有出头的机会吗?

        这是不是意味着我们可以直接舍去这个没有出头机会的元素呢?

        舍去了确实队列可以到[3,1,-1]的情况,之后来了个5,我们又该怎么办呢?

        不断看队尾,如果队尾小于5,把小于5的元素舍去,这样操作,我们就会把前面所有的元素舍去了。

        这样就能保证队列单调递减,而最大的元素无疑就是队头的元素。

        这个思路充分运用了双端队列的优势——能舍去队尾元素的同时也能舍去队头元素。

代码实现:

347.前 K 个高频元素

题目链接:. - 力扣(LeetCode)

题面:

        给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。

思路:

        本题要实现的内容无非三个:

  1. 要统计元素出现频率
  2. 对频率排序
  3. 找出前K个高频元素

        统计频率可以靠map映射,排序和找出就需要优先级队列完成了。

        优先级队列就是一个披着队列外衣的堆,因为优先级队列对外接口只是从队头取元素,从队尾添加元素,再无其他取元素的方式,看起来就是一个队列,因为堆的性质(本质是完全二叉树),可以做到自动排列队列默认是大根堆(堆头是最大元素),还有另一种常见的是小根堆(堆头是最小元素)。

        可能有人想当然就觉得要用大根堆,不是求最大频率的元素吗?

        然而我们用小根堆更好一些。这主要是因为堆中pop操作的是将队头弹出,而我们要靠堆存放频率大的元素,小的放堆头才是更好的选择。

        可能还有人会问:为什么不把map弄到数组里sort呢?

        这个想法一定没有比本方法好用:sort排序的是整个数组,而我们的做法是维护前k个有序的数组就可以了。

代码实现:       

总结:

文章链接:代码随想录 

文章摘要:

灵魂四问:

C++中stack,queue 是容器么?

:不是,栈和队列是容器适配器。

我们使用的stack,queue是属于那个版本的STL?

:(三个最为普遍的STL版本)

  1. HP STL 其他版本的C++ STL,一般是以HP STL为蓝本实现出来的,HP STL是C++ STL的第一个实现版本,而且开放源代码。

  2. P.J.Plauger STL 由P.J.Plauger参照HP STL实现出来的,被Visual C++编译器所采用,不是开源的。

  3. SGI STL 由Silicon Graphics Computer Systems公司参照HP STL实现,被Linux的C++编译器GCC所采用,SGI STL是开源软件,源码可读性甚高。

我们使用的STL中stack,queue是如何实现的?

:从下图中可以看出,栈和队列的内部结构,底层实现可以是vector,deque,list 都是可以的, 主要就是数组和链表的底层实现。

        我们常用的SGI STL,如果没有指定底层实现的话,默认是以deque为缺省情况下栈的底层结构。

        deque是一个双向队列,只要封住一段,只开通另一端就可以实现栈的逻辑了。

stack,queue 提供迭代器来遍历空间么?

答:都不提供迭代器。

结语

        通过两天栈和队列的学习,我掌握了栈和队列的性质以及运用,还接触了优先队列和双端队列的使用操作。虽然栈和队列的性质比较简单,但是围绕他们的深层次的知识点以及类似的其他结构还是有很多需要学习的。

  • 20
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第二十二天的算法训练营主要涵盖了Leetcode题目中的三道题目,分别是Leetcode 28 "Find the Index of the First Occurrence in a String",Leetcode 977 "有序数组的平方",和Leetcode 209 "长度最小的子数组"。 首先是Leetcode 28题,题目要求在给定的字符串中找到第一个出现的字符的索引。思路是使用双指针来遍历字符串,一个指向字符串的开头,另一个指向字符串的结尾。通过比较两个指针所指向的字符是否相等来判断是否找到了第一个出现的字符。具体实现的代码如下: ```python def findIndex(self, s: str) -> int: left = 0 right = len(s) - 1 while left <= right: if s[left == s[right]: return left left += 1 right -= 1 return -1 ``` 接下来是Leetcode 977题,题目要求对给定的有序数组中的元素进行平方,并按照非递减的顺序返回结果。这里由于数组已经是有序的,所以可以使用双指针的方法来解决问题。一个指针指向数组的开头,另一个指针指向数组的末尾。通过比较两个指针所指向的元素的绝对值的大小来确定哪个元素的平方应该放在结果数组的末尾。具体实现的代码如下: ```python def sortedSquares(self, nums: List[int]) -> List[int]: left = 0 right = len(nums) - 1 ans = [] while left <= right: if abs(nums[left]) >= abs(nums[right]): ans.append(nums[left ** 2) left += 1 else: ans.append(nums[right ** 2) right -= 1 return ans[::-1] ``` 最后是Leetcode 209题,题目要求在给定的数组中找到长度最小的子数组,
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值