Featured image of post Python 笔试备忘

Python 笔试备忘

笔试前看看

Python LeetCode & ACM笔试 极简速查表

一、 核心容器:初始化、拼接与类型转换

1. 列表 (List) -> 动态数组 / 栈

  • 创建与初始化:
    • 空列表: arr = []
    • 定长初始化: arr = [0] * n
    • 二维初始化: dp = [[0] * n for _ in range(m)] (严禁使用 [[0]*n]*m)
    • 推导式: arr = [x**2 for x in range(10) if x % 2 == 0]
  • 拼接与扩展:
    • + 运算符: [1, 2] + [3, 4] -> [1, 2, 3, 4] (产生新列表,耗时)
    • 原地扩展: arr.extend([3, 4]) (等价于按顺序 append,$O(K)$)
  • 操作: append(x) $O(1)$, pop() $O(1)$, arr[::-1] 翻转 $O(N)$, sort() 原地排序 $O(N \log N)$。

2. 集合 (Set) -> 哈希去重

  • 创建与初始化:
    • 空集合: s = set() (严禁使用 {},那是空字典)
    • 字面量: s = {1, 2, 3}
  • 拼接与运算:
    • 并集: s1 | s2s1.union(s2)
    • 交集: s1 & s2s1.intersection(s2)
    • 差集: s1 - s2
  • 操作: add(x) $O(1)$, remove(x) $O(1)$ (不存在会报错), discard(x) $O(1)$ (不存在不报错)。

3. 字典 (Dict) -> 哈希表

  • 创建与初始化:
    • 空字典: d = {}dict()
    • 默认字典: d = defaultdict(int) (访问不存在的键返回默认值)(from collections import defaultdict
    • 键值对: d = {'a': 1, 'b': 2}
  • 拼接与合并:
    • Python 3.9+: d3 = d1 | d2 (合并字典,同名键覆盖)
    • 原地更新: d1.update(d2)
  • 操作: d.get(key, default) (安全读取), key in d $O(1)$。

4. 字符串 (String) -> 不可变字符序列

  • 切片 (极其高频,极速操作):
    • s[:4] # “leet” (前 4 个字符)
    • s[-4:] # “code” (后 4 个字符)
    • s[::-1] # “edocteel” ($O(N)$ 极速反转)
  • 查找与判断:
    • s.find("etc") # 返回 2 (子串起始索引,找不到返回 -1,笔试首选)
    • s.startswith("le")# True
    • s.endswith("de") # True
    • s.isalnum() # True (判断是否只包含字母和数字,双指针判断回文时必用)
    • s.isdigit() # False (判断是否纯数字)
  • 替换与清理 (注意:必须重新赋值):
    • s2 = " a b c "
    • s2.strip() # “a b c” (默认袪除首尾所有空白符)
    • s2.replace(" ", "") # “abc” (极其好用的全量替换)

5. 元组 (Tuple) -> 不可变序列 / 可哈希键

  • 创建与初始化:
    • 空元组: t = ()
    • 单元素元组: t = (1,) (⚠️ 必须带逗号,否则 (1) 会被当作整数运算)
    • 常规元组: t = (1, 2, 3)
  • 核心特性与用途:
    • 可哈希 (Hashable): 因为绝对不可变,它是唯一能作为 Dict 键 (Key) 或存入 Set 的序列(List 绝对不行)。
    • 多维状态记录: BFS 搜索时记录坐标 visited.add((r, c));DP 记忆化 memo[(idx, weight)] = res
  • 操作与解包:
    • 极速解包: r, c = (0, 1) (多变量同时赋值)
    • 索引与切片: t[0], t[::-1] (与列表行为一致,但不能修改元素)
1
2
3
4
# enumarate 同时获取索引和值
arr = ['a', 'b', 'c']
for i, val in enumerate(arr):
    print(f"Index: {i}, Value: {val}")

6. 容器互相转换矩阵

转换方向语法说明
List -> Setset(arr)瞬间去重,常用于降维打击 $O(N)$ 查找
Set -> Listlist(s)集合转回数组,常用于去重后排序
String -> Listlist("abc")变为 ['a', 'b', 'c'],因为字符串不可变,需转列表修改
List -> String"".join(arr)高效拼接,arr 内部必须全是字符串元素
Dict -> Listlist(d.keys())
list(d.values())
分别提取字典的键或值构成列表
List <-> Tupletuple(arr)
list(t)
列表转元组以使其可哈希(存入 Set/Dict),或元组转列表以修改内容

二、 ACM 模式标准输入输出

处理国内笔试题(如牛客网)必备,避免 input() 导致超时或读取异常。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import sys

# 1. 万能读取法 (应对空格、换行混乱的输入)
# 将所有输入全部读入,打平为一个一维列表,后续通过迭代器或指针逐步提取
data = sys.stdin.read().split() 
if not data: exit()
iterator = iter(data)
n = int(next(iterator)) # 提取第一个数

# 2. 单行读取 (极速版)
def get_ints():
    return list(map(int, sys.stdin.readline().split()))

# 3. 矩阵读取 (读取 n 行 m 列)
n, m = get_ints()
matrix = [get_ints() for _ in range(n)]

# 4. 高效输出
# print 在大量输出时很慢,改用 sys.stdout.write
sys.stdout.write(" ".join(map(str, result_list)) + "\n")

三、 高频核心数据结构 (collections & heapq)

Python 循环结构极简速查

1. for 循环 (基于 range)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 基础遍历 [0, n-1]
for i in range(n): pass

# 区间遍历 [1, n-1]
for i in range(1, n): pass

# 倒序遍历 [n-1, 0] (左闭右开,步长-1)
for i in range(n - 1, -1, -1): pass

# 步长遍历 (每次+2)
for i in range(0, n, 2): pass

避坑:Python 中在 for 循环内修改 i 无效,会被下一轮自动重置。如需动态调整指针必须用 while

2. 数据遍历 (无索引依赖)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# 1. 仅遍历值
for val in arr: pass

# 2. 同时获取索引和值 (高频)
for i, val in enumerate(arr): pass

# 3. 多序列并行遍历 (以最短为准)
for v1, v2 in zip(arr1, arr2): pass

# 4. 集合遍历 (无序)
for x in my_set: pass

# 5. 字典遍历
for k in my_dict: pass            # 仅遍历键 (默认行为)
for v in my_dict.values(): pass   # 仅遍历值
for k, v in my_dict.items(): pass # 同时遍历键值 (高频)
# 注意:严禁在遍历 Set/Dict 时修改其大小 (add/remove/pop),否则报错

3. while 循环

1
2
3
4
5
6
7
# 1. 标准边界控制 (如二分查找)
while left <= right: pass

# 2. 容器判空 (代替 C++ 的 !q.empty())
# 空列表 []、空集合 set() 均等价于 False
while q: 
    node = q.popleft()

4. 控制流特有语法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# for...else / while...else 结构 (省去 bool 标记)
for x in arr:
    if x == target:
        break # 触发 break,直接跳出,不执行 else
else:
    # 循环自然跑完(未被 break 中断)时执行
    return "Not Found" 

# 基础控制符
continue # 跳过本次循环剩余代码,进入下一次
break    # 强制跳出当前所在的一层循环
pass     # 空语句占位符 (等价于 C++ 的 {})

5. 常用数据结构操作

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 1. 双端队列 (BFS 核心)
from collections import deque
q = deque([1, 2])
q.append(3)      # 尾部入队 O(1)
curr = q.popleft() # 头部出队 O(1) 

# 2. 自动初始化字典 (图论建图、归类核心)
from collections import defaultdict
adj = defaultdict(list) # 默认值为 []
adj[0].append(1)        # 免去 if 0 not in adj 的判断

# 3. 词频统计器
from collections import Counter
cnt = Counter("anagram") # {'a': 3, 'n': 1, 'g': 1, 'r': 1, 'm': 1}

# 4. 堆 / 优先队列 (Dijkstra、TopK 核心)
import heapq
arr = [3, 1, 2]
heapq.heapify(arr)       # 原地建小顶堆 O(N)
heapq.heappush(arr, 0)   # 插入 O(log N)
min_val = heapq.heappop(arr) # 弹出最小值 O(log N)
heapq.heappushpop(arr, 4) # 插入后弹出最小值 O(log N)
# 大顶堆技巧:压入 -x,弹出时再取负

四、 内置函数与语法糖

  • 极值与数学: float('inf'), float('-inf')pow(a, b, mod) 快速幂取模算法(比自己手写快)。divmod(a, b) 同时返回商和余数。
  • ASCII 转换: ord('a') -> 97, chr(97) -> ‘a’。
  • 字符串高频处理:
    • s.split() (默认处理所有连续空白符并丢弃空串)。
    • s.isalnum() (判断是否全为字母或数字,回文串常用)。
    • s.find(sub) (找子串,找不到返回 -1,严禁使用 index() 因为会抛异常报错)。
  • 高阶遍历:
    • for i, val in enumerate(arr): (同时拿索引和值)。
    • for x, y in zip(arr1, arr2): (双数组齐头并进)。
  • 排序:
    • arr.sort() # 默认升序,原地排序,适用于数字/字符串
    • arr.sort(reverse=True) # 降序排序
    • arr.sort(key=lambda x: x[0]) # 按元素的第一个字段排序(如区间、元组、二维数组)
    • arr.sort(key=lambda x: (x[0], -x[1])) # 多条件排序:优先按第一元素升序,相同则按第二元素降序
    • sorted(arr) # 返回新排序后的列表,不改变原数组
    • sorted(arr, key=..., reverse=...) # 一切排序技巧均可用
    • 例:intervals.sort(key=lambda x: x[0]) # 区间按左端点排序,区间合并/覆盖问题高频
  • 三元运算符(条件表达式):
    • 语法:a if 条件 else b (等价于 C/C++/Java 的 条件 ? a : b
    • 示例:res = x if x > 0 else -x # 取绝对值

五、 常用算法代码骨架

1. 二分查找 (标准库版)

自带的 bisect 库是 $O(\log N)$,直接替代手写二分。

1
2
3
4
5
6
import bisect
arr = [1, 2, 2, 4]
# 找第一个 >= x 的位置 (左侧插入点)
idx_left = bisect.bisect_left(arr, 2)  # 返回 1
# 找第一个 > x 的位置 (右侧插入点)
idx_right = bisect.bisect_right(arr, 2) # 返回 3

2. 图论 BFS 模板

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
step = 0
visited = set([start])
q = deque([start])
while q:
    size = len(q)
    for _ in range(size): # 按层扩展
        curr = q.popleft()
        if curr == target: return step
        for nxt in graph[curr]:
            if nxt not in visited:
                visited.add(nxt)
                q.append(nxt)
    step += 1

3. 并查集 (Union-Find)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class UnionFind:
    def __init__(self, size):
        # 初始化:每个人的老总都是自己
        self.parent = [i for i in range(size)]
        # 记录以 i 为根的集合的大小,初始都是 1
        self.size = [1] * size
        # 连通分量的数量(有多少个独立的帮派)
        self.count = size

    def find(self, i):
        # 路径压缩 (Path Compression)
        if self.parent[i] != i:
            self.parent[i] = self.find(self.parent[i])
        return self.parent[i]

    def union(self, i, j):
        root_i = self.find(i)
        root_j = self.find(j)
        
        # 已经是同一个老总,无需合并
        if root_i == root_j:
            return False
            
        # 按大小合并 (Union by Size):小树挂在大树下面
        if self.size[root_i] < self.size[root_j]:
            self.parent[root_i] = root_j
            self.size[root_j] += self.size[root_i]
        else:
            self.parent[root_j] = root_i
            self.size[root_i] += self.size[root_j]
            
        # 合并成功,独立帮派数量减一
        self.count -= 1
        return True
        
    def is_connected(self, i, j):
        # 判断两人是否连通
        return self.find(i) == self.find(j)

4. DPS

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def dfs_template(node, state_var):
    # 1. 递归终止条件 (Base Case)
    # 遇到空节点、越界,或者满足特定结算条件时,立刻向上层返回
    if not node:
        return
    if is_target_reached(node):
        process_result(node, state_var)
        return

    # 2. 处理当前层逻辑 (Process Current Node)
    # 根据题意,修改状态变量或记录当前节点的信息
    update_state(state_var, node)

    # 3. 递归下探 (Drill Down)
    # 遍历所有可能的下一个节点(如树的左右子树,图的邻居节点)
    # 注意:下探时必须传递更新后的状态变量
    dfs_template(node.left, next_state(state_var))
    dfs_template(node.right, next_state(state_var))

    # 4. 恢复当前层状态 (Restore State / Backtrack) - 可选
    # 如果 state_var 是全局变量或可变对象(如列表),在回溯时需要撤销第2步的修改
    # 如果 state_var 是按值传递(如数字相加),则不需要此步
    revert_state(state_var, node)

5. 01背包

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
def zero_one_knapsack(weights, values, capacity):
    n = len(weights)
    
    # 1. 定义与初始化 DP 数组
    # dp[j] 表示:当背包容量为 j 时,能获得的最大价值(或最小代价)
    # 如果求最大值,初始化为 0;如果求最小值,初始化为 float('inf')
    dp = [0] * (capacity + 1)
    
    # base case: 容量为 0 时,价值为 0
    dp[0] = 0 

    # 2. 外层循环:遍历每一个物品
    for i in range(n):
        w = weights[i]
        v = values[i]
        
        # 3. 内层循环:遍历背包容量(核心难点:必须倒序!)
        # 倒序的原因:dp[j] 的更新依赖于上一层状态的 dp[j-w]。
        # 如果正序遍历,dp[j-w] 会在当前物品这一层被提前更新,导致同一个物品被重复放入(这就变成了完全背包问题)。
        for j in range(capacity, w - 1, -1):
            
            # 4. 状态转移方程 (State Transition)
            # 决策:是不放这个物品(保持 dp[j]),还是腾出 w 的空间放入这个物品(dp[j - w] + v)?
            # 根据题意取 max 或 min
            dp[j] = max(dp[j], dp[j - w] + v)

    # 5. 返回最终状态
    return dp[capacity]

树图什么的

现实校准:LeetCode 考什么,不考什么

在你听到“红黑树”、“B+树”等高大上的名词时,需要首先明确工业界底层开发与 LeetCode 算法应试的绝对分界线

  • 红黑树 (Red-Black Tree) / AVL 树: 它们是自平衡二叉搜索树,为了解决普通二叉搜索树退化成链表的问题而生。但在 LeetCode 面试中,几乎绝对不会让你从零手写一棵红黑树(代码量极大且极易出错,通常需要几百行严密的旋转逻辑)。如果你在题目中需要用到自平衡树的特性(即保持动态有序并支持 $O(\log N)$ 查找),在 C++ 中直接使用 std::set / std::map,在 Java 中使用 TreeMap,在 Python 中则依赖第三方库 sortedcontainers 或使用 bisect 模块结合列表模拟。
  • LeetCode 的核心靶点: 是利用基础的二叉树、二叉搜索树 (BST)、字典树 (Trie) 以及基础图论(无向图/有向图的遍历、拓扑排序),来考察你的递归思维 (DFS)层级思维 (BFS)

以下是为你剥离冗余后,针对 LeetCode 场景的树与图 Cheat Sheet


1. 二叉搜索树 (BST - Binary Search Tree)

辩证本质: 树形结构中的“二分查找”。它将线性数组的查找效率从 $O(N)$ 降维至 $O(\log N)$,但代价是每次插入/删除都需要动态维护其严格的大小关系。

  • 核心物理规则: 对于任何一个节点,其左子树所有节点的值必小于该节点;其右子树所有节点的值必大于该节点。
  • 最强推论(必考点): 对 BST 进行中序遍历 (Inorder Traversal:左-根-右),得到的必定是一个严格递增的有序数组
  • 经典题型: 验证二叉搜索树(98)、二叉搜索树中第K小的元素(230)、修剪二叉搜索树(669)。

Python 模板:利用中序遍历验证 BST

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

def isValidBST(root: TreeNode) -> bool:
    # 辩证点:不要单纯只判断左孩子小于根、右孩子大于根。
    # 必须传递一个不断收紧的上下界,确保整棵子树都符合规则。
    def dfs(node, lower, upper):
        if not node:
            return True
        if node.val <= lower or node.val >= upper:
            return False
        # 往左走,上限变成当前节点的值;往右走,下限变成当前节点的值
        return dfs(node.left, lower, node.val) and dfs(node.right, node.val, upper)
        
    return dfs(root, float('-inf'), float('inf'))

2. 字典树 / 前缀树 (Trie)

辩证本质: 典型的“空间换时间”。通过将字符串拆解为字符并构建多叉树,将海量字符串的匹配时间复杂度,从 $O(N \times L)$ 极致压缩到 $O(L)$($L$ 为单个单词的长度),代价是需要极其庞大的节点内存。

  • 核心特征词: “前缀匹配”、“搜索联想”、“单词搜索”、“异或最大值(01字典树)”。
  • 物理结构: 根节点为空,每个节点包含一个字典(或长度为 26 的数组)指向下一个字符,以及一个布尔标志位表示“是否为单词结尾”。
  • 经典题型: 实现 Trie (前缀树)(208)、单词搜索 II(212 - Trie + DFS 的终极杀器)。

Python 模板:Trie 的标准实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class TrieNode:
    def __init__(self):
        self.children = {}  # 存储子节点,例如 {'a': TrieNode, 'b': TrieNode}
        self.is_end = False # 标识此处是否构成一个完整的单词

class Trie:
    def __init__(self):
        self.root = TrieNode()

    def insert(self, word: str) -> None:
        node = self.root
        for char in word:
            if char not in node.children:
                node.children[char] = TrieNode()
            node = node.children[char]
        node.is_end = True

    def search(self, word: str) -> bool:
        node = self.root
        for char in word:
            if char not in node.children:
                return False
            node = node.children[char]
        return node.is_end # 必须是单词结尾才算找到

3. 图 (Graph) 基础:无向图 vs 有向图

辩证本质: 树其实是图的一种极度受限的特例(树是没有环的连通无向图)。图抛弃了“父子关系”的严格层级,允许数据之间存在任意的网状联系。

  • 无向图 (Undirected Graph): 边是双向的。A 认识 B,B 必然认识 A。
    • 核心陷阱: 极易形成死循环死锁(如 A 走向 B,B 又走向 A)。
    • 破解之道: 无论 DFS 还是 BFS,必须使用 visited 集合来记录走过的节点,坚决不走回头路。
  • 有向图 (Directed Graph): 边是单向的。A 关注了 B,B 不一定关注 A。
    • 核心考点: 成环检测拓扑排序

4. 拓扑排序 (Topological Sort) - 针对有向无环图 (DAG)

辩证本质: 将一个存在依赖关系的网状图,拉平为一条线性的执行序列。如果图中存在环(如 A 依赖 B,B 依赖 A),则拓扑排序必然失败(发生死锁)。

  • 核心特征词: “课程表”、“编译依赖”、“任务调度”、“是否存在先后矛盾”。
  • 物理模型 (Kahn 算法):
    1. 统计所有节点的入度 (In-degree)(即有多少条边指向它,代表它被多少个前置条件卡着)。
    2. 将所有入度为 0 的节点(没有任何前置依赖的任务)放入队列。
    3. 弹出节点执行,并将其指向的所有邻居节点的入度减 1。
    4. 如果邻居入度降为 0,则加入队列。
  • 经典题型: 课程表(207)、课程表 II(210)。

Python 模板:利用 BFS (Kahn算法) 实现拓扑排序

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
from collections import deque, defaultdict

def canFinish(numCourses: int, prerequisites: list[list[int]]) -> bool:
    # 1. 初始化邻接表和入度数组
    graph = defaultdict(list)
    in_degree = [0] * numCourses
    
    # 2. 构建图 (prerequisites[i] = [a, b] 表示选 a 必须先学 b,即 b -> a)
    for course, pre in prerequisites:
        graph[pre].append(course)
        in_degree[course] += 1
        
    # 3. 将所有入度为 0 的节点(即不需要任何先修课的课程)入队
    queue = deque([i for i in range(numCourses) if in_degree[i] == 0])
    
    # 4. 记录已完成的课程数量
    completed_count = 0
    
    while queue:
        node = queue.popleft()
        completed_count += 1
        
        # 将依赖该课程的所有后续课程入度减 1
        for neighbor in graph[node]:
            in_degree[neighbor] -= 1
            # 一旦前置依赖全部解除,加入队列准备学习
            if in_degree[neighbor] == 0:
                queue.append(neighbor)
                
    # 辩证点:如果完成的数量等于总课程数,说明不存在环,可以学完。
    # 如果最后还有课程没学完(入度死活降不到0),说明图里必定存在互相依赖的“死锁环”。
    return completed_count == numCourses

六、 根据数据范围推断时间复杂度 (防超时指南)

机试时,先看题目给定的变量范围 $N$,直接反推该用什么算法:

  • $N \le 20$: 回溯法、状态压缩 DP $\rightarrow O(2^N)$ 或 $O(N!)$
  • $N \le 400$: 三重循环、Floyd 算法 $\rightarrow O(N^3)$
  • $N \le 2000$: 两重循环、普通 DP $\rightarrow O(N^2)$
  • $N \le 10^5$: 排序、堆、二分查找、线段树 $\rightarrow O(N \log N)$
  • $N \le 10^6$: 双指针、滑动窗口、单调栈、哈希表 $\rightarrow O(N)$
  • $N \ge 10^9$: 数学规律、快速幂、二分答案 $\rightarrow O(\log N)$ 或 $O(1)$

七、Leetcode Python 数据结构速成

已完成联网核对。前文提到的“有效的字母异位词”题号有误(LeetCode 24 实际为“两两交换链表中的节点”,242 才是“有效的字母异位词”),下表已修正。

这是一份纯粹用于检验 Python 数据结构熟练度的闭卷通关表:

题目号及名称核心知识点闭卷 AC 验收标准
125. 验证回文串字符串过滤、切片翻转熟练使用推导式 [c.lower() for c in s if c.isalnum()],用切片 s == s[::-1] 一行判断,不写双指针。
349. 两个数组的交集Set 的初始化与交集运算严禁手写两层循环,必须一句话搞定:return list(set(nums1) & set(nums2))
128. 最长连续序列Set 的 $O(1)$ 极速查找将数组转为 set,彻底理解并利用 num in num_set 的 $O(1)$ 特性防超时。
242. 有效的字母异位词词频统计 (Counter)严禁手写循环统计,直接引入 Counter,使用 return Counter(s) == Counter(t) 一行秒杀。
49. 字母异位词分组defaultdict、Tuple 作为哈希键熟练写出 d = defaultdict(list),深刻理解必须将排序后的字符串转为 tuple 才能作为字典的 key。
169. 多数元素字典遍历 / API 获取极值熟练手写字典遍历寻找最大值,或直接使用 Counter(nums).most_common(1)[0][0]
20. 有效的括号List 作为栈的使用熟练使用 append()pop(),并用静态字典 {')': '(', ']': '[', '}': '{'} 优雅映射替代大量 if-else
102. 二叉树的层序遍历deque 实现 BFS倒背如流 q = deque([root])q.popleft(),严禁在此处使用 list.pop(0)
200. 岛屿数量多维坐标的 Tuple 打包与 Set 去重在二维 BFS/DFS 中,极其熟练地将坐标打包成元组存入访问记录:visited.add((r, c))
215. 数组中的第K个最大元素heapq 核心 API熟练使用 heapq.heapify 以及维护大小为 $K$ 的小顶堆(heappushheappop)。
347. 前 K 个高频元素大顶堆技巧与复杂结构嵌套结合 Counter 统计频率,并熟练写出“取负数塞入小顶堆模拟大顶堆”的操作:heappush(hp, (-freq, num))
56. 合并区间列表的高阶排序 (lambda)不看资料直接写出按左端点升序排列的定制规则:intervals.sort(key=lambda x: x[0])
潇洒人间一键仙
使用 Hugo 构建
主题 StackJimmy 设计