算法面试通关 — 堆栈与队列
堆栈、队列(Stack、Queue)
堆栈、队列(Stack、Queue)
1. Stack(堆栈) - 先进先出 只有一个端
- Array or Linked List
2. Queue(队列) - 先进后出 有两端 一端进一端出
- Array or Linked List
Stack (堆栈)


常用数据结构操作

大O计数法

面试题
1 判断一个括号字符串是否有效
给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
每个右括号都有一个对应的相同类型的左括号。

https://leetcode.cn/problems/check-if-a-parentheses-string-can-be-valid/
左括号入栈,右括号出栈,最后判断栈是否为空

def isValid(s):
stack = []
paren_map = {')': '(', ']': '[', '}': '{'}
for c in s:
if c not in paren_map:
stack.append(c)
elif not stack or paren_map[c] != stack.pop():
return False
return not stack
2 用队列实现栈
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。
实现 MyStack 类:
void push(int x) 将元素 x 压入栈顶。
int pop() 移除并返回栈顶元素。
int top() 返回栈顶元素。
boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。
注意:
你只能使用队列的基本操作 —— 也就是 push to back、peek/pop from front、size 和 is empty 这些操作。
你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。

class MyQueue(object):
def __init__(self):
"""
Initialize your data structure here.
"""
self.input_stack = []
self.output_stack = []
def push(self, x):
"""
Push element x to the back of queue.
:type x: int
:rtype: None
"""
self.input_stack.append(x)
def pop(self):
"""
Removes the element from in front of queue and returns that element.
:rtype: int
"""
if self.empty():
return None
else:
if len(self.output_stack):
return self.output_stack.pop()
else:
# for i in xrange(0, len(self.input_stack)):
# self.output_stack.append(self.input_stack.pop())
length = len(self.input_stack)
self.output_stack = map(lambda x: self.input_stack.pop(), range(0, length))
return self.output_stack.pop()
def peek(self):
"""
Get the front element.
:rtype: int
"""
if self.empty():
return None
else:
if len(self.output_stack):
return self.output_stack[-1]
else:
# for i in xrange(0, len(self.input_stack)):
# self.output_stack.append(self.input_stack.pop())
length = len(self.input_stack)
self.output_stack = map(lambda x: self.input_stack.pop(), range(0, length))
return self.output_stack[-1]
def empty(self):
"""
Returns whether the queue is empty.
:rtype: bool
"""
return bool(len(self.input_stack) == 0 and len(self.output_stack) == 0)
3 用栈实现队列
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):
实现 MyQueue 类:
void push(int x) 将元素 x 推到队列的末尾
int pop() 从队列的开头移除并返回元素
int peek() 返回队列开头的元素
boolean empty() 如果队列为空,返回 true ;否则,返回 false
说明:
你 只能 使用标准的栈操作 —— 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。
你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。

class MyQueue:
def __init__(self):
self.list = []
# 进队
def push(self, x: int) -> None:
self.list.append(x)
# 返回队首元素并出队
def pop(self) -> int:
x = self.list[0]
self.list = self.list[1:]
return x
# 返回队首元素
def peek(self) -> int:
return self.list[0]
# 判断队列是否为空
def empty(self) -> bool:
if len(self.list) == 0:
return True
else:
return False
if __name__ == "__main__":
obj = MyQueue()
obj.push(1)
obj.push(2)
print(obj.peek())
print(obj.pop())
print(obj.empty())
优先队列 (了解背后的实现机制即可)
- 正常⼊、按照优先级出
2种实现方式
- 1. Heap (Binary, Binomial, Fibonacci) 队
-
Binary Search Tree 二叉树搜索
面试题

设计一个找到数据流中第 k 大元素的类(class)。注意是排序后的第 k 大元素,不是第 k 个不同的元素。
请实现 KthLargest 类:
KthLargest(int k, int[] nums) 使用整数 k 和整数流 nums 初始化对象。
int add(int val) 将 val 插入数据流 nums 后,返回当前数据流中第 k 大的元素。
解题思路: 使用最小堆来实现, 堆的长度就是k
import heapq
class Solution(object):
@staticmethod
def findKthLargest(nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
heap = []
heapq.heapify(heap)
for n in nums:
if len(heap) < k:
heapq.heappush(heap, n)
elif n > heap[0]:
heapq.heapreplace(heap, n)
return heap[0]
if __name__ == '__main__':
res = Solution.findKthLargest([1, 6, 8, 9], 3)
print(res)
2 滑动窗口最大值
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。

题解:双端队列实现 比较的都是下标,基于下标来维护滑动窗口
首先窗口向右滑动的过程就是将窗口最左侧的元素删除,同时在窗口的最右侧添加一个新的元素,这就要用到双端队列,然后找双端队列中的最大元素。
那剩下就是如何找到滑动窗口中的最大值。
那我们就可以只在队列中保留可能成为窗口最大元素的元素,去掉不可能成为窗口中最大元素的元素。
想象一下,如果要进来的是个值大的元素,那一定会比之前早进去的值小的元素晚离开队列,而且值大的元素在,都没值小的元素啥事,所以值小的元素直接弹出队列即可。
这样队列里其实维护的一个单调递减的单调队列。
题解:https://leetcode.cn/problems/sliding-window-maximum/solutions/1212012/acm-xuan-shou-tu-jie-leetcode-hua-dong-c-i3wj/?q=%E6%BB%91%E5%8A%A8%E7%AA%97%E5%8F%A3%E6%9C%80%E5%A4%A7%E5%80%BC&orderBy=most_relevant&languageTags=python3
res 队列存下标 deque 队列存具体值
class Solution:
@staticmethod
def maxSlidingWindow(nums, k: int): # nums 数组 k 窗口的大小
# 如果数组为空或 k = 0,直接返回空
if not nums or not k:
return []
# 如果数组只有1个元素,直接返回该元素
if len(nums) == 1:
return [nums[0]]
# 初始化队列和结果,队列存储数组的下标
queue = []
res = []
for i in range(len(nums)):
# 如果当前队列最左侧存储的下标等于 i-k 的值,代表目前队列已满。
# 但是新元素需要进来,所以列表最左侧的下标出队列
if queue and queue[0] == i - k:
queue.pop(0)
# 对于新进入的元素,如果队列前面的数比它小,那么前面的都出队列
while queue and nums[queue[-1]] < nums[i]:
queue.pop()
# 新元素入队列
queue.append(i)
# 当前的大值加入到结果数组中
if i >= k - 1:
res.append(nums[queue[0]])
return res
if __name__ == '__main__':
res = Solution.maxSlidingWindow([1, 3, -1, -3, 5, 3, 6, 7], 2)
print(res)

浙公网安备 33010602011771号