牛客算法--第四章

牛客算法–第四章

题目一
设计一个有 getMin 功能的栈
【题目】
实现一个特殊的栈,在实现栈的基本功能的基础上,再实现返回栈中最小元素的
操作。
【要求】
1.peek、pop、push、getMin 操作的时间复杂度都是 O(1)。
2.设计的栈类型可以使用现成的栈结构。

总结,这道题暂时提供两种解法,两种解法的前提都用到了两个栈,一个数据栈datastack,一个帮助栈minstack:

第一种,依次压栈,如果datastack为空,就把相应的data压入datastack和minstack;如果datastack不为空,就把data和minstack.top()元素比较,求较小的一个min,并且minstack.push(min);
       依次出栈,datastack.pop()的同时,minstack.pop()。

第二种,依次入栈,如果依次压栈,如果datastack为空,就把相应的data压入datastack和minstack;如果datastack不为空,就把data和minstack.top()元素比较,如果data小于等于top元素,就入栈minstack.push(min);否则,不进行压入minstack操作。

	依次出栈,datastack.top()元素的对应min值就是minstack.top()元素。如果出栈的时候两边的top元素相等,两个栈都进行pop操作。否则,只有datastack栈进行pop操作。



题目二
由两个栈组成的队列
【题目】
编写一个类,用两个栈实现队列,支持队列的基本操作(add、poll、peek)。

总结,这道题关键是把握两个关键点,运用data栈和help栈:

1.data栈中的数据向help栈中进行倒入时,help栈一定要empty;
2.data栈中的数据向help栈中进行倒入时,必须将data栈中的元素全部倒入help栈,也就是要求一次性倒空为止。



题目三
由两个队列组成的栈
【题目】
编写一个类,用两个队列实现栈,支持栈的基本操作(push、poll、peek)。

总结,没别的,这道题不能出错。用到两个queue。pushqueue,popqueue;

pushqueue执行push操作,将所有数据存入pushqueue,pop的时候,将pushqueue从头开始到倒数第二个元素push进popqueue,然后将pushqueue中的仅剩的最后一个元素输出,然后将popqueue中的所有元素再入队到pushqueue队列中。











题目四
如何仅用递归函数和栈操作逆序一个栈
【题目】
一个栈依次压入 1、2、3、4、5,那么从栈顶到栈底分别为 5、4、3、2、1。将
这个栈转置后,从栈顶到栈底为 1、2、3、4、5,也就是实现栈中元素的逆序,
但是只能用递归函数来实现,不能用其他数据结构。

总结,当解这道题的时候,递归其实运用的是函数栈,我们可以模拟一下如果存在两个栈,我们会如何操作,满足要求。

这里,首先需要用到一个算法原型:将栈底元素返回并且将其从原来的栈中删除。

针对算法原型如何操作呢?运用栈和递归。如果模拟两个栈,就是一个栈中的数据push到另一个栈,直到第一个栈中元素只有一个的时候,就将其返回到一个变量中保存起来,并且将其弹出第一个栈,然后将第二个栈中的数据都依次push进第一个栈。

本道题的话,求解的过程中用到了上面的算法原型,算法原型是栈+递归形式的。本道题的求解同样是栈+递归,在递归中用到了算法原型,所以本质上其实是栈+递归的双层嵌套。

这道题是要求得到逆序的结果,也就是我们在函数中用算法原型得到栈底元素,并且将其从栈中删除。直到栈为空的时候,就是递归返回条件,直接return,然后先是递归调用原来的函数,然后将得到的栈底元素push进入栈中。

具体的话,看代码会比较直观。

题目四
字符串表达式求值
【题目】
给定一个字符串 str,str 表示一个表达式,其中只可能有整数、加减乘除符号
和左右括号,返回公式的计算结果。
【举例】
str="48*((70-65)-43)+8*1",返回-1816。
str="3+1*4",返回 7。
str="3+(1*4)",返回 7
【说明】
1.可以认为给定的字符串一定是正确的表达式,即不需要对 str 做公式有效性
检查。
2.如果是负数,就需要用括号括起来,比如"4*(-3)"。但如果负数作为公式的
开头或括号部分的开头,则可以没有括号,比如"-3*4"和"(-3*4)"都是合法的。
3.不用考虑计算过程中会发生溢出的情况。

这道题没什么好讲的,之前自己写过一个很挫的代码,长度早跑到100行开外了,所以见到左神用50行左右的代码解决,还是很厉害的。就总结一下关键点和左神代码的思想。

关键点:运用递归,将左右括号里面的内容看作一个子计算表达式。
函数实现的就是将其括号里的内容计算出对应的值,并且总的表达的下一步下标返回,就是返回的是两个值,可以用结构体,也可以用一个两位的数组。

还需要注意的就是连续数字字符处理成同一数字;
还有就是加减乘除的优先级的自我设定。这个代码还是尽力理解吧,没什么好说的了。

题目五
生成窗口最大值数组
【题目】
有一个整型数组 arr 和一个大小为 w 的窗口从数组的最左边滑到最右边,窗口每
次向右边滑一个位置。
例如,数组为[4,3,5,4,3,3,6,7],窗口大小为 3 时:
[4 3 5] 4 3 3 6 7 窗口中最大值为 5
4 [3 5 4] 3 3 6 7 窗口中最大值为 5
4 3 [5 4 3] 3 6 7 窗口中最大值为 5
4 3 5 [4 3 3] 6 7 窗口中最大值为 4
4 3 5 4 [3 3 6] 7 窗口中最大值为 6
4 3 5 4 3 [3 6 7] 窗口中最大值为 7
如果数组长度为 n,窗口大小为 w,则一共产生 n-w+1 个窗口的最大值。
请实现一个函数。
输入:整型数组 arr,窗口大小为 w。
输出:一个长度为 n-w+1 的数组 res,res[i]表示每一种窗口状态下的最大值。
以本题为例,结果应该返回{5,5,5,4,6,7}。

这道题的算法原型 用到了双端队列,刚开始,不理解,真的十分困难。
用左神举的例子:

 arr	5 4 3 6 
 下标    0 1 2 3

当l在5左边,r在3的右边,6的左边的时候,双端队列里面的是前面3个元素的下标:0 1 2;当r到了6的右边,此时就会把双端队列中的所有比6小的值的下标从双端队列的尾部弹出,也就是空了,把6的下标从双端队列的尾部弹进去,就是双端队列中的元素只有6的下标3了。
关键的地方,就是移动l的时候需要判断双端队列的头部的下标是否已经过期了,如果过期,就将其从双端队列的头部弹出。

以上的方法中,所有的数都是进队列一次,出队列一次,所以复杂度是O(N)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值