1. 引言

刷题时经常被一些“平时知道,用的时候忘了”的操作卡住,比如 indexmaxpopreverse,以及 Counterdefaultdictdeque 等。更重要的是,力扣习惯了核心代码模式,面对 ACM 模式的输入输出会手忙脚乱。本文统一以 def main(): ... if __name__ == "__main__": main() 的骨架,整理常用数据类型的方法、collections 高频工具,以及各类输入输出样例,不涉及具体算法,专做基础补全。

2. 常用数据类型与方法速查

这里只列刷题最常用的方法,按可变/不可变、返回值、原地操作分类,避免混淆。

2.1 列表 list

li = [3, 1, 2]

li.append(4)                    # 末尾追加
li.pop()                        # 弹出末尾,返回元素
li.pop(1)                       # 按下标弹出
li.insert(1, 5)                 # 在下标 1 插入 5
li.remove(3)                    # 按值删除第一个匹配项
li.index(2)                     # 返回第一个 2 的下标
li.count(2)                     # 统计 2 的出现次数
li.sort()                       # 原地排序,返回 None
li.sort(reverse=True)           # 降序
sorted_li = sorted(li)          # 返回新列表,不改变原列表
sorted_li = sorted(li, reverse=True)
li.reverse()                    # 原地反转,返回 None
reversed_li = list(reversed(li))# 返回迭代器,需转列表
max(li)                         # 最大值
min(li)                         # 最小值
sum(li)                         # 求和
len(li)                         # 长度
all(li)                         # 全部为 True
any(li)                         # 任一为 True

# 列表推导式
squares = [x**2 for x in range(10)]

2.2 字符串 str

s = "hello world"

s.split()                       # ['hello', 'world']
s.split('o')                    # ['hell', ' w', 'rld']
s.find('w')                     # 返回第一个下标,未找到返回 -1
s.index('w')                    # 同上,未找到抛 ValueError
s.count('l')                    # 统计子串次数
s.replace('world', 'python')    # 替换
s.startswith('he')              # 是否以 he 开头
s.endswith('ld')                # 是否以 ld 结尾
' '.join(['a', 'b', 'c'])       # 连接列表元素
s.strip()                       # 去除首尾空白
s.lstrip() / s.rstrip()
s.isdigit()                     # 是否为全数字
s.isalpha()                     # 是否为全字母
s.upper() / s.lower()
s[::-1]                         # 反转字符串

2.3 字典 dict

d = {'a': 1, 'b': 2}

d['a']                          # 取值(键不存在抛 KeyError)
d.get('c', 0)                   # 安全取值,不存在返回 0
d.keys() / d.values() / d.items()
for k, v in d.items(): ...

d.pop('a')                      # 弹出键并返回值
d.popitem()                     # 弹出最后插入的键值对(3.7+ 有序)
d.update({'c': 3})              # 合并字典
del d['b']                      # 删除键值对

2.4 集合 set

s = {1, 2, 3}
s.add(4)
s.remove(2)                     # 元素不存在抛 KeyError
s.discard(5)                    # 安全删除
s.pop()                         # 随机弹出
s1 & s2                         # 交集
s1 | s2                         # 并集
s1 - s2                         # 差集
s1 ^ s2                         # 对称差集

2.5 栈、队列与堆

栈直接用 list 模拟:append + pop。队列推荐 collections.deque(见第 3 节)。堆使用 heapq

import heapq

heap = []
heapq.heappush(heap, 3)
heapq.heappush(heap, 1)
val = heapq.heappop(heap)        # 弹出最小值
heapq.heapify([3, 1, 2])         # 原地建堆
# 大顶堆可以通过存储负数实现

3. collections 高频工具

3.1 Counter —— 计数器

from collections import Counter

cnt = Counter("abracadabra")
cnt['a']                         # 5
cnt.most_common(2)               # [('a', 5), ('b', 2)]
cnt.update("aaaa")               # 增加计数
cnt.subtract("aa")               # 减少计数

3.2 defaultdict —— 带默认值的字典

from collections import defaultdict

d = defaultdict(int)             # 默认值 0
d['x'] += 1                      # 不需要判断键是否存在

d = defaultdict(list)            # 默认空列表
d['y'].append(1)

d = defaultdict(set)             # 默认空集合

3.3 deque —— 双端队列

from collections import deque

q = deque([1, 2, 3])
q.append(4)                      # 右侧入队
q.appendleft(0)                  # 左侧入队
q.pop()                          # 右侧出队
q.popleft()                      # 左侧出队
q.rotate(1)                      # 右移 1 位

4. ACM 模式输入输出骨架

所有示例统一采用以下模板:

import sys

def main():
    pass

if __name__ == "__main__":
    main()

使用 sys.stdin.read()/sys.stdin.readline() 处理输入,比 input() 更快,且更适配多行场景。

4.1 单行输入

样例: 3 5 7

def main():
    line = sys.stdin.readline().strip()
    nums = list(map(int, line.split()))
    print(nums)           # [3, 5, 7]

4.2 多行输入(已知行数)

样例:

3        # 接下来有 3 行
1 2 3
4 5 6
7 8 9
def main():
    n = int(sys.stdin.readline())
    matrix = []
    for _ in range(n):
        row = list(map(int, sys.stdin.readline().split()))
        matrix.append(row)
    print(matrix)

4.3 无限输入(直到 EOF)

样例:

1 2
3 4
5 6
(EOF)
def main():
    for line in sys.stdin:
        a, b = map(int, line.split())
        # 处理每一行

4.4 多组测试用例(首行给出 T)

样例:

2
3 4
5 5
def main():
    data = sys.stdin.read().strip().split()
    t = int(data[0])
    idx = 1
    for _ in range(t):
        n = int(data[idx]); idx += 1
        m = int(data[idx]); idx += 1
        # 处理一组

4.5 单行输入一个列表(带空格)

样例: 1 2 3 4 5

def main():
    arr = list(map(int, sys.stdin.readline().split()))

4.6 单行输入一个字符串(可能含空格)

def main():
    s = sys.stdin.readline().strip()        # 去除末尾换行和空格

若要保留行内空格,用 .rstrip('\n')力扣输入通常没有多余空格。

4.7 输入多行字符串列表

样例:

abc
def
ghi
def main():
    n = int(sys.stdin.readline())
    strs = [sys.stdin.readline().strip() for _ in range(n)]

或用无限输入:

def main():
    strs = [line.strip() for line in sys.stdin]

5. 常见数据结构的输入输出写法

5.1 链表

力扣核心模式给出链表头节点;ACM 模式通常给一个数组,需要自己构建链表并返回头节点。输出也常需打印链表整个序列。

class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

def build_linked_list(nums):
    """从列表构建链表,返回头节点"""
    dummy = ListNode()
    cur = dummy
    for num in nums:
        cur.next = ListNode(num)
        cur = cur.next
    return dummy.next

def print_linked_list(head):
    """打印链表(假设节点值用 -> 连接)"""
    res = []
    while head:
        res.append(str(head.val))
        head = head.next
    print("->".join(res))

def main():
    # 样例输入:1 2 3 4
    nums = list(map(int, sys.stdin.readline().split()))
    head = build_linked_list(nums)
    # 调用解题函数
    # ...
    print_linked_list(head)

5.2 二叉树

ACM 模式通常给层序遍历序列(null/None 表示空节点),需要构建树;输出常为前中后序或层序。

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

def build_tree(vals):
    """vals: 列表,None 表示空节点(层序)"""
    if not vals:
        return None
    root = TreeNode(vals[0])
    queue = deque([root])
    i = 1
    while queue and i < len(vals):
        node = queue.popleft()
        if i < len(vals) and vals[i] is not None:
            node.left = TreeNode(vals[i])
            queue.append(node.left)
        i += 1
        if i < len(vals) and vals[i] is not None:
            node.right = TreeNode(vals[i])
            queue.append(node.right)
        i += 1
    return root

def main():
    line = sys.stdin.readline().strip()
    # 输入如 "1,2,3,null,4"
    parts = line.replace("null", "None").split(",")
    vals = [int(x) if x != "None" else None for x in parts]
    root = build_tree(vals)
    # ...

5.3 图(邻接表/邻接矩阵)

图常以边列表形式给出,例如第一行 n m 表示节点数、边数,接下来 m 行每行 u v 表示边。

无向图邻接表:

def main():
    n, m = map(int, sys.stdin.readline().split())
    graph = [[] for _ in range(n)]
    for _ in range(m):
        u, v = map(int, sys.stdin.readline().split())
        graph[u].append(v)
        graph[v].append(u)

有向带权图邻接表:

def main():
    n, m = map(int, sys.stdin.readline().split())
    graph = [[] for _ in range(n)]
    for _ in range(m):
        u, v, w = map(int, sys.stdin.readline().split())
        graph[u].append((v, w))

6. 更复杂的输入样例

6.1 不定个数的一行列表

直接读一行并按空格分割:

def main():
    arr = list(map(int, sys.stdin.readline().split()))

6.2 多行不定个数,每行不同格式

def main():
    lines = sys.stdin.read().strip().splitlines()
    for line in lines:
        if not line:
            continue
        parts = line.split()
        # 根据 parts[0] 判断处理方式

6.3 包含字符串和数字混合的行

def main():
    tokens = sys.stdin.readline().split()
    name = tokens[0]
    age = int(tokens[1])

7. 总结

本文整理了 Python 刷题中容易被遗忘的常用方法,以及从简单到复杂的 ACM 输入输出写法,全部以 def main() + if __name__ == "__main__": main() 统一呈现。建议将此文加入收藏,碰到陌生输入或遗忘方法时快速查阅。后续如需补充其他数据结构或技巧,可随时扩充。

更多推荐