文章总览:YuanDaiMa2048博客文章总览
🔗 查看完整专栏(LeetCode基础算法专栏)
专栏文章
点击阅读:Python 数据结构与语法速查笔记
点击阅读:哈希表基础原理与题目说明
点击阅读:双指针基础原理与题目说明
点击阅读:滑动窗口基础原理与题目说明
点击阅读:队列与单调队列基础原理与题目说明
特别说明: 本文为个人的 LeetCode 刷题与学习笔记,内容仅供学习与交流使用,禁止转载或用于商业用途。需要强调的是,文中的题目解法不一定是最优解(可能存在时间或空间复杂度的进一步优化空间),主要目的是分享个人的解题思路与逻辑实现,仅供参考。 笔记内容为个人理解与总结,可能存在疏漏或偏差,欢迎读者自行甄别并交流探讨。

Python 数据结构与语法速查笔记
日常以Python开发或刷题时,熟练掌握并区分各种数据结构的底层表现和正确语法至关重要。本文对Python中常用的数据结构进行了统一格式的整理,方便对比与记忆。
一、栈 (Stack) - 使用 list
- 特点 :后进先出(LIFO)。Python中没有专门的Stack类,直接使用列表
[]即可实现栈的功能。 - 适用场景:括号匹配、单调栈(求下一个更大元素)、DFS(深度优先搜索)迭代实现。
🛠️ 核心操作速查
| 操作类型 | 代码语法 | 时间复杂度 | 说明 |
|---|---|---|---|
| 创建/初始化 | stack = [] |
O(1) | 直接初始化为空列表 |
| 加入 (Push) | stack.append(val) |
O(1) | 在列表末尾添加元素(压栈) |
| 删除 (Pop) | val = stack.pop() |
O(1) | 弹出并返回列表最后一个元素(出栈) |
| 访问/查看 | top = stack[-1] |
O(1) | 查看栈顶元素(注意需先判空 if stack:) |
⚠️ 注意 :不要滥用
stack.insert(0, val)或stack.pop(0)来模拟栈底操作,这会导致 O(N) 的时间复杂度,请始终在尾部进行append和pop。
二、队列与双端队列 (Queue / Deque)
- 特点 :先进先出(FIFO)或 双端操作。不要用
list模拟队列 (因为list.pop(0)是 O(N) 复杂度),建议使用标准库的collections.deque。 - 适用场景:BFS(广度优先搜索)、滑动窗口、维护区间状态。
🛠️ 核心操作速查
| 操作 | 语法 | 时间复杂度 | 说明 |
|---|---|---|---|
| 创建/初始化 | deq = deque() |
O(1) | 需 from collections import deque |
| 加入队尾 | deq.append(x) |
O(1) | 常规入队(尾部添加) |
| 加入队首 | deq.appendleft(x) |
O(1) | 双端队列特有(头部添加) |
| 删除队首 | deq.popleft() |
O(1) | 常规出队(FIFO),弹出头部 |
| 删除队尾 | deq.pop() |
O(1) | 双端队列特有,弹出尾部 |
三、哈希表 (Hash Table)
哈希表通过键值对快速存取,平均时间复杂度为 O(1)。在 Python 中分为四种常用类型:dict、set、Counter、defaultdict。
在 Python 底层,collections.Counter 和 collections.defaultdict 本质上都是继承自 dict 的子类。因此,在执行删除操作时候,在字典中用的 del 和 pop(),完全可以直接用在这两个数据结构上。
del 和 pop 的主要区别在于:
del hash_dict[key]:直接在内存中删除该键值对。但是,如果这个 key 在字典中不存在,它会无情地抛出 KeyError 报错。
val = hash_dict.pop(key, None):不仅会删除该键值对,还会把被删除的值返回给你。更重要的是,加上第二个参数(如 None)后,如果 key 不存在,它不会报错,而是返回 None,这可以避免很多因为边界条件引起的意外崩溃。
1. 字典 (dict)
- 特点:标准的键值对(Key-Value)映射。
| 操作类型 | 代码语法 | 说明 |
|---|---|---|
| 创建/初始化 | hash_dict = {} |
初始化空字典 |
| 加入/更新 | hash_dict[key] = val |
若 key 存在则覆盖,不存在则创建 |
| 删除 | val = hash_dict.pop(key, None) |
安全删除并返回值。不存在时返回设定的 None |
| 访问/查询 | val = hash_dict.get(key, 0) |
安全访问。不存在时返回设定的默认值 0,不报错 |
2. 集合 (set)
- 特点 :无序且元素唯一的集合,主要用于去重和快速查找。
| 操作类型 | 代码语法 | 说明 |
|---|---|---|
| 创建/初始化 | nums_set = set() |
初始化空集合(注意不能用 {}) |
| 加入 | nums_set.add(val) |
添加单个元素,若已存在则忽略 |
| 删除 | nums_set.discard(val) |
安全删除。若元素不存在也不会报错 |
| 访问/查询 | if val in nums_set: |
O(1) 判断元素是否存在 |
如果这个元素在集合中不存在,使用
nums_set.remove(val)会抛出 KeyError 报错,而nums_set.discard(val)则什么都不会发生,所以 discard 更"安全",省去了先判断if val in nums_set:的步骤。
3. 计数器 (collections.Counter)
- 特点:自带统计功能的哈希表,自动计算频率。
| 操作类型 | 代码语法 | 说明 |
|---|---|---|
| 创建/初始化 | freq = Counter(nums) |
传入列表等迭代器,返回 {元素: 频次} 字典 |
| 加入/修改 | freq[key] += 1 |
增加频次,键不存在时默认从 0 开始加 |
| 高级操作 | freq.most_common(k) |
返回出现频次最高的 k 个元素:[(val, freq), ...] |
4. 默认字典 (collections.defaultdict)
- 特点:访问不存在的键时,会自动创建默认值,适合分组或构建邻接表。
| 操作类型 | 代码语法 | 说明 |
|---|---|---|
| 创建(列表默认) | adj = defaultdict(list) |
默认值为空列表 [] |
| 加入/修改 | adj[node].append(neighbor) |
直接 append,无需判断 node 键是否已存在 |
| 创建(数字默认) | count = defaultdict(int) |
默认值为数字 0 |
四、优先队列 / 堆 (Heap)
- 特点 :底层是一棵完全二叉树,Python 内置的是小顶堆(根节点最小) 。基于普通的
list实现。 - 适用场景:动态求极值、Top K 问题。
🛠️ 核心操作速查
| 操作 | 语法 | 时间复杂度 | 说明 |
|---|---|---|---|
| 创建/初始化 | heap = [] |
O(1) | 底层载体也是普通列表 |
| 原址建堆 | heapq.heapify(nums) |
O(N) | 将无序列表直接原地转化为小顶堆 |
| 加入 (Push) | heapq.heappush(heap, x) |
O(log N) | 将 x 放入堆并自动调整维持堆性质 |
| 删除 (Pop) | heapq.heappop(heap) |
O(log N) | 弹出并返回堆顶(最小)元素 |
| 查看堆顶 | heap[0] |
O(1) | 索引 0 永远是堆顶极小值 |
| 大顶堆技巧 | heappush(heap, -x) |
- | 存入时取负数,弹出时再取负数恢复 |
五、有序数组
数组排序 (sort 与 sorted)
| 操作类型 | 代码语法 | 时间复杂度 | 说明 |
|---|---|---|---|
| 原地排序 | arr.sort() |
O(N log N) | 直接在原列表上修改,无返回值。可加 reverse=True 实现降序 |
| 生成新排序列表 | new_arr = sorted(arr) |
O(N log N) | 不改变原列表,返回一个全新的已排序列表 |
六、自定义数据结构 (链表与树)
在刷题(如 LeetCode)中,链表和树通常需要自己定义类。
1. 单链表节点 (Linked List)
py
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
# 创建与遍历演示
head = ListNode(1)
head.next = ListNode(2)
curr = head
while curr:
print(curr.val)
curr = curr.next
2. 二叉树节点 (Binary Tree)
py
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
# 创建与初始化演示
root = TreeNode(1)
root.left = TreeNode(2)
root.right = TreeNode(3)
数据结构在 CPython 底层的本质
[] 列表 ------ 本质:动态数组 (Dynamic Array)
- 涵盖结构:普通列表、栈 (Stack)、堆 (Heap / heapq)、有序数组 (bisect)。
- 原理解析:它不是链表,而是一块连续的内存空间,里面存的是指向实际对象的指针。当数组满了,它会申请一块更大的新内存,把旧数据拷贝过去(过度分配机制)。
- 致命缺陷:因为是连续内存,如果你删除了第 0 个元素(pop(0)),后面的所有元素都要往前挪动一位,时间复杂度为 O(N)。但尾部的 append 和 pop() 只需操作指针,所以是 O(1)。
collections.deque (双端队列)
- 涵盖结构:队列 (Queue)、滑动窗口。专门为了解决上述 [] (动态数组) 头部操作极慢的问题。
- 原理解析:底层结构是块状双向链表 (Doubly Linked List of Blocks)。它由一个个固定大小的"块"组成,块之间用双向链表连接。在头部或尾部添加/删除元素时,只需在最边缘的块操作或新建块,不需要移动其他元素,实现严格的 O(1)。
{} 字典/集合 ------ 本质:哈希表 (Hash Table)
- 涵盖结构:字典 (dict)、集合 (set)、计数器 (Counter)、默认字典 (defaultdict)。
- 原理解析:通过哈希函数计算键(Key)的索引位置,实现 O(1) 的极速存取。Python 使用"开放寻址法"解决哈希冲突。
- 注意:
- {} 默认是空字典。空集合必须用 set()。
- {"a": 1} 是字典, {1, 2} 是集合。
() 元组 ------ 本质:静态只读数组
- 涵盖结构:不可变序列。
- 原理解析:一旦创建,内存大小和内容就完全固定,不支持任何增删改操作。
- 用途:正因为其不可变(可哈希),只有 () 可以作为 {} (字典/集合) 的 Key,而 [] 绝对不行(例如用 (x,y) 记录网格访问状态)。
💡 综合记忆口诀
- 栈要后出 :只用
[],只调append()和pop()。 - 队要先出 :引
deque,尾进append(),头出popleft()。 - 频率/哈希 :去重找
set,映射找dict,防越界找defaultdict,统计找Counter。 - 最值/Top K :引
heapq,默认小堆(取大变负),操作带前缀heappush/heappop。