基本知识点
- 栈:先进后出,队列:先进先出
- 栈和队列都既能用数组实现,又能用链表实现
- 栈和队列的基本操作:pop()、push()、top()/peek()、size()
- 比较复杂的队列:双端队列、优先级队列;其中,优先级队列实际上不是顺序结构而是堆结构,它根据队列元素的优先级弹出元素
- 图的深度优先遍历用栈实现,宽度优先遍历用队列实现
- 递归函数实际上用了提供的函数系统栈,所以用递归实现的功能都能用非递归实现
经典例题
- 实现特殊功能的栈,使它实现栈基本功能的同时,可以查找当前栈的最小元素。要求:时间复杂度为O(1),可以使用现成的栈结构。
1、用两个栈实现,stack_data用于存储数据,stack_min用于存储当前最小元素,入栈过程中,如果当前元素小于stack_min中栈顶元素,则同时将其压入stack_min中,否则只压入stack_data中,出栈过程中,如果当前元素等于stack_min中栈顶元素,则同时stack_min执行出栈,否则只有stack_data出栈。
2、用两个栈实现,stack_data用于存储数据,stack_min用于存储当前最小元素,入栈过程中,如果当前元素小于stack_min中栈顶元素,则同时将其压入stack_min中,压入stack_data的同时将stack_min的栈顶重复压栈,出栈过程中,stack_data和stack_min同步出栈。 - 用两个栈实现队列,支持add()、poll()、peek()操作。
1、采用两个栈,stack_push用于入队,stack_pop用于出队,具体实现中,只要将stack_push中的元素以此出栈的同事压入stack_pop中,stack_pop中的出栈顺序即为出队顺序,但需要注意以下两点
1)stack_push中的元素必须一次性压入stack_pop、2)当stack_pop补位空时不能将stack_push倒入stack_pop中。 - 实现栈的逆序。要求:只能用递归和栈本身的操作
实现过程中用到两个递归函数,它们的介绍如下:
递归函数1:实现移除栈底元素并返回实现get()功能。实现过程:从递归前一层进入下一层之前执行pop操作,到达栈底时返回,最后一层直接返回pop出的元素而不压栈,其余各层收到下一层的返回后,将返回值返回给上一层,将自己pop出的元素压栈。
递归函数2:实现栈的逆序。实现过程:从递归前一层进入下一层之前执行get()操作,到栈底返回前要将当前层get到的元素压栈后返回。 - 已知栈,请将该栈从顶到底从大到小排序。要求:只许申请一个栈和新的变量,不能申请额外的数据结构。
需要用到两个栈:stack和help,stack依次执行出栈操作的同时和help中的栈顶元素进行比较,如果当前元素小于栈顶元素,则将其压入help,反之则help依次执行pop的同时将元素压入stack,直到当前元素大于stack中刚刚被弹出的元素,此时将stack中刚刚弹出的元素压入help中,再继续遍历stack直到栈底。 - 已知数组A的长度为N,窗口W的长度为w,设计算法返回w在A中滑动过程中每个位置窗口中的最大值
利用双端队列实现窗口最大值的更新(时间复杂度为O(N)):设双端队列qmax,用来存储数组A中的下标
队尾操作过程:遍历 数组A,当遍历到i时,如果qmax为空i直接从队尾入队列,如果qmax不为空则访问队尾下标j,如果A[j]>A[i],则i从队尾入队,如果A[j] <= A[i]则j从队尾弹出,重复考察当前队尾元素,当当前队尾下标A[j] > A[i]时停止弹出队尾,i从队尾入队
实际上队尾操作过程使得qmax始终存储着从队头到队尾从大到小排列的元素的下标。
对头操作过程:如果对头下标j = i - w,说明该对头已过期,需要弹出对头小标,如果对头下标j > i - w,则对头下标对应的值即为当前窗口位置的最大值。 - 给定没有重复元素的数组arr,写出生成这个数组的MaxTree的算法。要求:时间复杂度为O(N)
MaxTree:1)为二叉树,arr中每个值对应二叉树的一个节点。2)包括MaxTree在内的每一颗子树上,值最大的节点都是根节点。
用到两个hash表,第一个hash表存储每个数组元素左边第一个比它大的树,第二个hash表用来存储每个数组元素右边第一个比它大的数,两个hash表中相同索引对应的数中最大的数即为该索引的根节点,若两边都不存在比它大的数,那么它即为整个MaxTree根节点。利用栈可以实现这连个hash表。
网友评论