Python 笔试备忘
笔试前看看
1. 输入输出处理 (Input/Output)
Python ACM 模式输入模板
在笔试(ACM模式)中,Python 的 input() 有时较慢,推荐使用 sys.stdin.readline。
| |
常见输入模式案例 (Case Study)
案例:跳过首行/处理固定行数
很多题目第一行是 Case 数 T,后面跟 T 行数据。
推荐写法 (Standard Way):
利用 sys.stdin 是一个迭代器的特性,先手动读取第一行消耗掉,再循环。
| |
案例:N 个整数可能跨行 (The read() trick)
题目说“输入 N 个整数”,但数据可能写在同一行,也可能分多行。
千万不要只用 sys.stdin.readline().split(),因为它只读一行,如果数据换行了就会报错。
万能写法 (Recommended):
使用 sys.stdin.read().split() 读取所有剩余输入,它会自动忽略所有空白符(空格、换行、制表符)。这是 ACM 模式处理复杂输入的神器。
| |
案例:单行秒杀 (One-Liner)
如果确定输入即为一行空格分隔的整数(如:1 2 3 4 5),直接使用 map。
| |
案例:二维矩阵处理 (Matrix)
题目输入 n 行 m 列的矩阵。
| |
输出技巧
- 列表转字符串:
print(" ".join(map(str, ans))) - 格式化输出 (Formatting):
- 保留小数:
f"{x:.3f}"(保留 3 位小数,自动四舍五入) ->1.235 - 补前导零:
cnt.zfill(5)或f"{cnt:05d}"->00123 - 百分比:
f"{x:.2%}"->12.34%
- 保留小数:
- 快速输出: 必须输出大量行 (10^5 级) 时,
print可能超时。1sys.stdout.write('\n'.join(map(str, result_list)) + '\n')
2. 循环与控制流 (Loops & Control Flow)
while 循环 (While Loop)
- 特定次数或条件: 比如 BFS 队列循环,二分查找。
| |
for 循环 (For Loop)
range() 函数:
range(start, stop, step)左闭右开。range(5)->0, 1, 2, 3, 4range(1, 4)->1, 2, 3range(5, 0, -1)->5, 4, 3, 2, 1(倒序遍历常考)
enumerate(): 同时获取索引和值 (推荐)。
| |
- zip(): 同时遍历两个列表。
| |
- else 子句: 当循环正常结束(没有被 break 中断)时执行。
- 常见场景:判断质数,查找失败后的兜底逻辑。
| |
3. 基础数据结构 (Data Structures)
常用容器
1. 列表 (List)
- 创建:
arr = [](空列表)arr = [0] * n(初始化 n 个 0, 比如 DP 数组)matrix = [[0] * m for _ in range(n)](n 行 m 列二维数组,千万别用[[0]*m]*n)
- 常用操作:
arr.append(x): 末尾添加 O(1)arr.pop(): 弹出末尾 O(1)arr.insert(i, x): 在 i 处插入 O(N) (慎用)len(arr): 长度 O(1)arr.sort(): 原地排序 O(N log N)arr.reverse(): 原地翻转 O(N)
- 切片 (Slicing):
arr[start:end:step]arr[::-1]: 翻转列表
2. 集合 (Set)
- 创建:
s = set()(空集合,注意不是 {},{} 是空字典)s = {1, 2, 3}s = set(arr)(列表转集合去重)
- 常用操作:
s.add(x): 添加 O(1)s.remove(x): 删除 O(1) (不存在报错)x in s: 判断存在 O(1)
- 集合运算:
s1 | s2(并),s1 & s2(交),s1 - s2(差)
3. 字典 (Dict / HashMap)
- 创建:
d = {}(空字典)d = {'a': 1, 'b': 2}
- 常用操作:
d['k'] = v: 设置/更新val = d.get('k', default): 安全获取 (不存在返回 default)key in d: 判断 key 是否存在 O(1)del d['k']: 删除 key
- 遍历:
for k, v in d.items(): ...(遍历键值对)for k in d: ...(只遍历键)
高级数据结构 (collections / heapq)
4. 双端队列 (collections.deque)
- 比 list 强在哪:
list.pop(0)是 O(N) 的(因为要移动数组),而deque.popleft()是 O(1) 的。 - BFS 必备:
| |
5. 计数器 (collections.Counter)
- 作用: 快速统计元素频率,实际上是一个 Dict 的子类。
| |
6. 默认字典 (collections.defaultdict)
- 作用: 自动处理 key 不存在的情况,省去
if key not in d的判断。
| |
7. 堆 (Heaps / Priority Queue)
- 作用: 动态维护最小值/最大值,插入和删除最值都是 O(log N)。
- 注意: Python 只有最小堆。想用最大堆?存入负数
-val。
| |
3. 常用内置函数及技巧 (Built-in Functions & Tricks)
1. 字符与编码 (ASCII)
处理字符串偏移(如 ‘a’->‘b’)时必用。
ord(char): 字符 -> ASCII 数值。ord('a')是 97,ord('A')是 65,ord('0')是 48。
chr(int): ASCII 数值 -> 字符。chr(97)是 ‘a’。
| |
2. 进制转换
bin(n): 转二进制字符串 (e.g.,'0b101').hex(n): 转十六进制字符串 (e.g.,'0xa').int(string, base): 任意进制转十进制。int('101', 2)-> 5int('A', 16)-> 10
3. 数学与数字处理
- 大整数 (Big Int): Python 的
int是任意精度的(自动扩容),不会溢出。不用担心 C++ 中的intvslong long问题,可以直接计算超大整数。 divmod(a, b): 返回(a // b, a % b),商和余数。pow(a, b, mod): 快速幂求模(a ** b) % mod,比(a**b)%mod快得多。abs(x): 绝对值。round(x, n): 四舍五入保留 n 位小数。math模块:math.ceil(x),math.floor(x): 向上/向下取整 (注意:int默认是向 0 取整)。math.gcd(a, b): 最大公约数。math.lcm(a, b): 最小公倍数 (Python 3.9+)。math.pi: 圆周率 (3.1415926…),比用 3.14 精确。math.sqrt(x): 平方根 (返回 float)。math.isqrt(x): 整数平方根 (返回 int, 向下取整, 比 floor(sqrt) 准)。math.inf: 无穷大 (常用于初始化最小值min_val = float('inf'))。
- 注意:
/得到的是float,整数整除必须用//。
4. 字符串操作 (Strings)
字符串是不可变对象 (Immutable),所有修改操作都会返回新字符串。
大小写:
s.lower(),s.upper(): 转小写/大写s.capitalize(): 首字母大写s.title(): 每个单词首字母大写
查找与判断:
s.startswith(prefix),s.endswith(suffix): 前后缀判断s.find(sub): 返回第一个索引,找不到返 -1 (推荐)s.index(sub): 返回第一个索引,找不到报错 (慎用)s.count(sub): 统计子串出现次数s.isdigit(): 是否全数字s.isalpha(): 是否全字母s.isalnum(): 是否全数字或字母
拆分与合并:
s.strip(): 去除两端空白 (经常用于处理 input)s.split(sep): 按 sep 分割,默认按空白符 (空格、换行、制表)line = " a b "; line.split()->['a', 'b'](自动去空,结果无需再 strip)
sep.join(iterable): 将列表组合成字符串 (效率高,千万别用+循环拼接)' '.join(['a', 'b'])->'a b'(空格连接)"".join(['a', 'b'])->'ab'(无缝拼接,替代s += x)
List <-> Str 互转 (修改字符串技巧):
list(s): 字符串转字符列表 (为了修改)。s = "abc"; chars = list(s) # ['a', 'b', 'c']chars[0] = 'X'
"".join(chars): 列表转回字符串。new_s = "".join(chars) # "Xbc"
替换与切片:
s.replace(old, new, count): 替换,count 可选替换次数s[::-1]: 字符串翻转 (最快写法)
5. 高阶函数与数据处理 (Functional & Data)
学会这些,一行代码顶十行。
map(function, iterable)
- 作用: 将
function作用于iterable中的每一个元素。 - 返回: 迭代器 (iterator)。需要用
list()包裹才能看到完整列表(除非只是用来遍历或求和)。 - 常见用法:
- 类型转换:
map(int, ['1', '2'])->[1, 2] - 多变量赋值:
a, b = map(int, input().split())
- 类型转换:
filter(function, iterable)
- 作用: 保留
function(x)为True的元素。 - 用法:
nums = [1, 2, 3, 4]evens = list(filter(lambda x: x % 2 == 0, nums))->[2, 4]
lambda 表达式 (匿名函数)
- 作用: 定义短小的、一次性的函数。
- 语法:
lambda arguments: expression - 场景: 配合
sort,max,map,filter使用。- 自定义排序: 按元组第二个元素排序
arr.sort(key=lambda x: x[1]) - 自定义最大值规则:
longest = max(strings, key=lambda s: len(s))
- 自定义排序: 按元组第二个元素排序
reduce(function, iterable) (from functools)
- 作用: 对序列进行累积操作(折叠)。
- 用法:
from functools import reduceproduct = reduce(lambda x, y: x * y, [1, 2, 3, 4])-> 24
sum(iterable, start)
- 作用: 求和。不要忘了如果元素是列表,可以用
sum展平一层(虽然慢点)。 - 用法:
sum([1, 2, 3])-> 6sum([[1, 2], [3, 4]], [])->[1, 2, 3, 4](慎用,O(N^2))
sorted(iterable, key=…, reverse=…)
- 作用: 返回一个新的已排序列表(不改变原列表)。
- 区别:
list.sort()是原地排序,无返回值。 - Tip: 只要是可以迭代的对象(字符串、元组)都可以丢给
sorted。sorted("bca")->['a', 'b', 'c']
6. 其他常用技巧
- 解包 (Unpacking):
a, b = b, a(交换);x, *rest = [1, 2, 3](x=1, rest=[2,3]). - Zip: 同时遍历两个列表
for x, y in zip(list1, list2):. - Enumerate: 带索引遍历
for i, val in enumerate(list):. - Any/All:
if any(x > 0 for x in nums):(是否存在);if all(...)(是否所有).
4. 常见算法模板 (Algorithms)
1. 查找与二分 (Binary Search)
Python 标准库 bisect 非常好用。
bisect.bisect_left(arr, x): 寻找插入点,使得左边都< x(即第一个>= x的位置)。bisect.bisect_right(arr, x): 寻找插入点,使得左边都<= x(即第一个> x的位置)。
也可手动实现二分:
| |
2. 双指针 (Two Pointers) / 滑动窗口 (Sliding Window)
常用于处理数组、字符串子串问题。
| |
3. 搜索 (BFS / DFS)
BFS (最短路径/层序遍历):
| |
DFS (全排列/连通性):
| |
Tip: 遇到 RecursionError 需要增加递归深度:sys.setrecursionlimit(2000)
4. 并查集 (Union-Find)
处理集合合并、连通分量问题。
| |
5. 动态规划 (Dynamic Programming)
- 背包问题 (0/1 背包,完全背包)
- 股票买卖
- 编辑距离,最长公共子序列 (LCS)
关键是定义状态
dp[i][j]和状态转移方程。
| |
5. 时空复杂度 (Complexity)
时间复杂度优化 Tips
- 避免列表查找:
if x in list是 O(N),改为if x in set是 O(1) 平均。 - 字符串拼接: 永远不要用
s += "a"在循环中拼接字符串(O(N^2)),使用"".join(list_of_strings)(O(N))。 - 输入输出: 大量数据必须用
sys.stdin.readline和sys.stdout.write。 - 排序: Python 的 Timsort 非常快,但如果只需 top K,用
heapq.nlargest更优。 - 递归: 深度过深会爆栈
RecursionError,记得sys.setrecursionlimit(20000)。 - 列表生成:
[x*2 for x in huge_list]比append快,也会比map好调试(虽然 map 有时极微快)。 - 缓存/记忆化: 使用
@functools.lru_cache(None)装饰器自动缓存递归结果 (DP)。
空间复杂度优化 Tips
- 生成器 (Generators): 处理大序列尽量用生成器表达式
(x**2 for x in range(1000000))而不是列表[...],这就只占一个迭代器内存。 - 原地操作: 尽量使用
nums.sort()(in-place) 而不是sorted(nums)(new list),除非需要保留原数组。 - 稀疏数组: 遇到很大范围但稀疏的数据,用
dict或defaultdict代替大数组。 - Slot: 在类中使用
__slots__可以极大减少对象内存占用(笔试通常不用,工程中有用)。 - Itertools: 善用
itertools.islice,chain,count等,避免生成中间列表。
常见复杂度参考
- N <= 20: O(2^N) DFS/Backtracking
- N <= 100: O(N^4) DP
- N <= 500: O(N^3) Floyd/DP
- N <= 2000: O(N^2) Bubble Sort/DP
- N <= 10^5: O(N log N) Sort/Heap/Merge Sort
- N <= 10^6: O(N) Hash/Two Pointers/Linear Scan
- N > 10^8: O(log N) Binary Search/Math
祝好运!