导航菜单

栈与队列

栈和队列是两种重要的线性数据结构,它们遵循不同的操作规则。栈遵循 LIFO(Last In First Out,后进先出),队列遵循 FIFO(First In First Out,先进先出)。掌握栈和队列的应用对于解决许多算法问题至关重要。

栈(Stack)

栈的特点

  • LIFO 原则:最后进入的元素最先出来
  • 基本操作:push(入栈)、pop(出栈)、peek(查看栈顶)
  • 应用场景:表达式求值、括号匹配、函数调用栈、DFS

栈的实现

class Stack:
    def __init__(self):
        self.items = []
    
    def push(self, item):
        self.items.append(item)
    
    def pop(self):
        if self.is_empty():
            raise IndexError("Stack is empty")
        return self.items.pop()
    
    def peek(self):
        if self.is_empty():
            raise IndexError("Stack is empty")
        return self.items[-1]
    
    def is_empty(self):
        return len(self.items) == 0
    
    def size(self):
        return len(self.items)

栈的应用

1. 括号匹配

def is_valid_parentheses(s):
    stack = []
    mapping = {')': '(', '}': '{', ']': '['}
    
    for char in s:
        if char in mapping:
            if not stack or stack.pop() != mapping[char]:
                return False
        else:
            stack.append(char)
    
    return not stack

2. 表达式求值

def evaluate_expression(tokens):
    stack = []
    
    for token in tokens:
        if token in ['+', '-', '*', '/']:
            b = stack.pop()
            a = stack.pop()
            if token == '+':
                stack.append(a + b)
            elif token == '-':
                stack.append(a - b)
            elif token == '*':
                stack.append(a * b)
            else:
                stack.append(int(a / b))
        else:
            stack.append(int(token))
    
    return stack[0]

队列(Queue)

队列的特点

  • FIFO 原则:最先进入的元素最先出来
  • 基本操作:enqueue(入队)、dequeue(出队)、front(查看队首)
  • 应用场景:BFS、任务调度、消息队列

队列的实现

from collections import deque

class Queue:
    def __init__(self):
        self.items = deque()
    
    def enqueue(self, item):
        self.items.append(item)
    
    def dequeue(self):
        if self.is_empty():
            raise IndexError("Queue is empty")
        return self.items.popleft()
    
    def front(self):
        if self.is_empty():
            raise IndexError("Queue is empty")
        return self.items[0]
    
    def is_empty(self):
        return len(self.items) == 0
    
    def size(self):
        return len(self.items)

队列的应用

BFS(广度优先搜索)

def bfs(graph, start):
    queue = deque([start])
    visited = {start}
    result = []
    
    while queue:
        node = queue.popleft()
        result.append(node)
        
        for neighbor in graph[node]:
            if neighbor not in visited:
                visited.add(neighbor)
                queue.append(neighbor)
    
    return result

单调栈(Monotonic Stack)

单调栈是一种特殊的栈,栈中的元素保持单调性(递增或递减)。

应用场景

  • 找到每个元素左边/右边第一个比它大/小的元素
  • 计算最大矩形面积
  • 接雨水问题

示例:找到每个元素右边第一个更大的元素

def next_greater_element(nums):
    stack = []
    result = [-1] * len(nums)
    
    for i in range(len(nums)):
        while stack and nums[stack[-1]] < nums[i]:
            index = stack.pop()
            result[index] = nums[i]
        stack.append(i)
    
    return result

示例:最大矩形面积

def largest_rectangle_area(heights):
    stack = []
    max_area = 0
    
    for i, height in enumerate(heights):
        while stack and heights[stack[-1]] > height:
            h = heights[stack.pop()]
            w = i if not stack else i - stack[-1] - 1
            max_area = max(max_area, h * w)
        stack.append(i)
    
    while stack:
        h = heights[stack.pop()]
        w = len(heights) if not stack else len(heights) - stack[-1] - 1
        max_area = max(max_area, h * w)
    
    return max_area

单调队列(Monotonic Queue)

单调队列是一种特殊的队列,队列中的元素保持单调性。

应用场景

  • 滑动窗口最大值/最小值
  • 动态规划优化

示例:滑动窗口最大值

from collections import deque

def max_sliding_window(nums, k):
    dq = deque()
    result = []
    
    for i in range(len(nums)):
        # 移除窗口外的元素
        while dq and dq[0] < i - k + 1:
            dq.popleft()
        
        # 维护单调递减队列
        while dq and nums[dq[-1]] < nums[i]:
            dq.pop()
        
        dq.append(i)
        
        # 窗口大小达到 k 时,记录最大值
        if i >= k - 1:
            result.append(nums[dq[0]])
    
    return result

优先队列(Priority Queue / Heap)

优先队列是一种特殊的队列,元素按照优先级出队。

堆(Heap)实现

import heapq

# 最小堆(默认)
heap = []
heapq.heappush(heap, 3)
heapq.heappush(heap, 1)
heapq.heappush(heap, 2)
print(heapq.heappop(heap))  # 1

# 最大堆(使用负数)
heap = []
heapq.heappush(heap, -3)
heapq.heappush(heap, -1)
heapq.heappush(heap, -2)
print(-heapq.heappop(heap))  # 3

应用场景

  • Top K 问题
  • 合并 K 个有序链表
  • 中位数查找

示例:合并 K 个有序链表

import heapq

def merge_k_lists(lists):
    heap = []
    
    # 初始化堆
    for i, node in enumerate(lists):
        if node:
            heapq.heappush(heap, (node.val, i, node))
    
    dummy = ListNode(0)
    current = dummy
    
    while heap:
        val, i, node = heapq.heappop(heap)
        current.next = node
        current = current.next
        
        if node.next:
            heapq.heappush(heap, (node.next.val, i, node.next))
    
    return dummy.next

常见题目

1. 有效的括号

def is_valid(s):
    stack = []
    mapping = {')': '(', '}': '{', ']': '['}
    
    for char in s:
        if char in mapping:
            if not stack or stack.pop() != mapping[char]:
                return False
        else:
            stack.append(char)
    
    return not stack

2. 每日温度

def daily_temperatures(temperatures):
    stack = []
    result = [0] * len(temperatures)
    
    for i, temp in enumerate(temperatures):
        while stack and temperatures[stack[-1]] < temp:
            index = stack.pop()
            result[index] = i - index
        stack.append(i)
    
    return result

3. 滑动窗口最大值

from collections import deque

def max_sliding_window(nums, k):
    dq = deque()
    result = []
    
    for i in range(len(nums)):
        while dq and dq[0] < i - k + 1:
            dq.popleft()
        
        while dq and nums[dq[-1]] < nums[i]:
            dq.pop()
        
        dq.append(i)
        
        if i >= k - 1:
            result.append(nums[dq[0]])
    
    return result

总结

栈和队列是算法面试中的重要数据结构:

  1. :LIFO 原则,用于括号匹配、表达式求值、DFS
  2. 队列:FIFO 原则,用于 BFS、任务调度
  3. 单调栈:维护单调性,用于找更大/更小元素
  4. 单调队列:滑动窗口问题
  5. 优先队列:Top K 问题、合并有序序列

掌握这些数据结构及其应用,能够帮助你解决许多算法问题。


接下来,让我们学习树、字典树和堆,这是更复杂的树形数据结构。

搜索