1.设计一个有getmin功能的栈
思路:创建一个栈叫minstack,维护一个从栈底到栈顶的递减栈。
压栈时原栈正常压入,在minstack栈中如果value大于栈就不压入,如果小于等于就压栈。这样就维护了一个从底到顶的降序序列
出栈时原栈正常出栈,在minstack栈中如果等于栈顶元素就出栈。
2.由两个栈组成的队列
思路:两个栈--s1只入队和s2只出队,入队操作直接放入s1即可,出队操作把s1出栈到s2然后将栈顶出栈返回,再将s2出栈并且入栈到s1保持原状。
扩展:用两个队列实现一个堆栈
思路:两个队列--s1只入栈和s2只出栈,元素入栈放入s1,元素出栈把s1出队并且入队s2再将s2出队入队到s1在将最后一个元素返回。
3.求最短通路径
0代表有路,1代表无路,从左上角到右下角的最短路径。
思路一:使用dfs遍历每次都有四种方向但是要判断是否通路或者是否走过了,所有路径找到最小的那个。
4.判断括号的有效性
思路一:使用栈进行模拟,栈里面只存储左括号。
思路二:使用两个计数指针,需要保证每次右括号数量都要小于等于左括号,然后在最终判断看数量是否相同。
5.滑动窗口的最大值
思路:使用队列(双端队列)维护一个从队头到队尾递减的序列,
- 如果当前值大于队尾值,则队尾出队列,直到不大于为止
- 如果当前值小于队尾值,则入队
- 如果当前值的下标 - 队头的下标等于窗口大小,则队头过期需要出栈
- 如果队头元素的下标 i>=k-1,则输出一个结果
def maxSlidingWindow(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: List[int]
"""
if(nums==[]): return []
res = []
queue = []
for i in range(len(nums)):
while(queue!=[] and nums[queue[-1]]<nums[i]):
queue.pop()
if(queue==[] or nums[queue[-1]]>=nums[i]):
queue.append(i)
if(i-queue[0]>=k):
queue.pop(0)
if(i>=k-1):
res.append(nums[queue[0]])
return res
6.给你一个数组,找出数组中每个数左边离它最近的比它大的数和右边离它最近的比它大的数。
思路:维护一个单调递减的栈结构
如果入栈元素大于栈顶元素,栈顶出栈,并记录出栈元素的信息(右边离他最近比他大的数是入栈元素,左边离他最近比他大的数是目前的栈顶元素)
如果入栈元素小于栈顶元素,元素入栈
如果相等需要额外判断
如果元素全部入栈,出栈操作时,会记录出栈元素的信息(右边没有比他大的数,左边离他最近比他大的数是目前的栈顶元素)
7.直方图最大矩形面积
思路:维护一个从栈底到栈顶递增的栈,就是为了先要确定当前栈顶元素的左边界,然后如果当前元素小于堆顶元素那么当前元素就是右边界,如此就可以确定以当前栈顶元素为最低点的边界,就可以计算面积了。
如果当前元素大于等于栈顶元素,入栈
如果当前元素小于栈顶元素,则确定了栈顶元素的右边界,栈维护了左边界,栈顶元素的面积为:
height[stack.pop()]*( i - stack[-1] - 1 ) if(stack==[]) 将stack[-1]换成-1(没有左边界)
最后栈不为空就出栈,说明栈顶元素没有右边界将i换成n即可。(如果右边有比他小的,该元素肯定已经出栈了)
8.求一个数组中最大值减去最小值 小于等于 num 的子数组数量(要求O(N))
【分析】:这里有两个结论
- 如果子数组 arr[i..j] 满足条件,那么 arr[k..l](i <= k <= l <= j)都满足条件,即若一个数组满足条件,它的所有子数组肯定满足条件。[max 变小 - min 变大 <= num 肯定成立]
- 如果子数组 arr[i..j] 不满足条件,那么 arr[k..l] (k <= i,I >= j) 都不满足条件,即若一个数组不满足条件,所有包含它的数组肯定都不满足条件。【[max变大 - min变小 >= num肯定成立]
【步骤】:
- 准备两个双端队列,一个 maxQueue 是窗口内最大值更新结构(单调递减),一个 minQueue 是窗口内最小值更新结构(单调递增),left、right 表示窗口的左右边,窗口范围为 【left , right - 1】;
- 以 left 开头的情况下,right 往外扩,扩到不达标就停【因为再往外肯定也不达标】,
- 以 left 开头的子数组有多少个【这些子数组都达标的】;left 右移一位,然后重复上一步。