栈的问题

对于栈一类的问题,个人感觉可能会很“复杂”,但是不会是特别“难于理解”,解题的时候一定要把过程想得很清楚。

 

leetcode值得刷的题

1. 复杂过程仔细分析的

42. Trapping Rain Water

84. Largest Rectangle in Histogram 

超级相似的两道题,不过水这个因为有连续性可以用双指针,最大直方图还是要老老实实用栈来做,其核心思路是如何计算以某一列为高的矩形的面积,整体来说,就是维护一个高度递增的栈,如果线性扫描的结果不满足这个性质,就pop出来操作,rightBound就是当前扫描节点,leftBound就是pop出来这个高度后栈顶元素的下标。

 

2.看似是栈的问题其实不是

239. Sliding Window Maximum

316. Remove Duplicate Letters

 

3.栈和队列相互的题

用栈实现队列(2个栈是必须的!push o(n) pop o(1)的操作,以及 push o(1 ) pop o(1) 两种)

用队列实现栈 (2个队列, push - O(1), pop O(n) 的操作,以及 push o(n) pop o(1) 两种 1个队列 push - O(n), pop O(1) )

155. Min Stack

没说明好说的~保存topmost即可,不过注意一个细节! Integer 可不能用 == 号!

这里有一个pop最大的操作,看看他是如何实现O(lgN)的时间复杂度的删除的!!其实核心还是对数据结构的理解!!

https://leetcode.com/articles/max-stack/

 

扩展:如何用一个数组实现三个栈!?

维护三个栈的栈顶指针和当前栈顶指针cur

每个元素位置需要维护他的上一个元素指针

pop(),cur要有对应响应,往回缩或者不动(比如栈顶)

push(),cur要对应响应,往前挪动到第一个空的位置!

http://www.code123.cc/763.html

 

4.线性扫描的问题

一般优化思路的时间复杂度可能是这样的:

暴力O(n^2) -> 开启递归/二分 O(nlgn) -> 线性扫描/动态规划(剪枝) O(n)

动态规划可以理解为剪枝的搜索,线性扫描其实就是洞悉了问题的规律,栈是线性扫描里面用得比较多的问题

239. Sliding Window Maximum

Follow up:

《程序员代码面试指南》

栈的问题_第1张图片

核心思路思路还是滑动窗口最大值的思想。

生成两个双端队列qmax和qmin,当子数组为arr[i..j]时,qmax维护了窗口子数组arr[i..j]的最大值更新的结构,qmin维护了窗口子数组arr[i..j]的最小值更新的结构。当子数组arr[i..j]向右扩一个位置变成arr[i..j+1]时,qmax和qmin结构可以在O(1)的时间内更新,并且可以在相同的时间内得到arr[i..j+1]的最大值和最小值。同时可以得出两个结论:

  • 如果子数组arr[i..j]满足条件,那么arr[k..l](i<=k<=l<=j)都满足条件。
  • 如果子数组arr[i..j]不满足条件,那么arr[k..l](k<=i<=j<=l)都不满足条件。

设计过程如下:

1.生成qmax和qmin,同时生成两个整型变量i和j,表示子数组的范围,即arr[i..j],生成整型变量res,表示所有满足条件的子数组数量。

2.令j不断向右移动(j++),表示arr[i..j]一直向右扩大,不断更新qmax和qmin结构。一旦出现arr[i..j]不满足条件的情况,j向右扩的过程停止,此时arr[i..j-1]、arr[i..j-2]、arr[i..j-3]、……、arr[i..i]都是满足条件的。也就是说满足条件的个数为j - i,即令res = j - i 。

3.完成步骤2,再令i向右移动一个位置,并对qmax和qmin进行更新,此时是arr[i+1..j]窗口的最大值和最小值的更新结构。然后反复重复步骤2。

4.根据步骤2和3,依次求出以arr[0]、arr[1]……、arr[N]作为第一个元素的子数组中满足条件的数量分别有多少个,累积起来的数量就是最终的结果。

整个过程由于小标值最多进qmax和qmin一次和出一次,所以过程的时间复杂度为O(N)。

 

5.计算器相关题

 

你可能感兴趣的:(数据结构与算法,leetcode,数据结构与算法,栈)