Python 基础 / 06
输入输出与 ACM 模式
在 LeetCode 核心代码模式中,平台负责把输入变成参数;在 ACM 模式中,你必须完成完整流程:
原始文本 -> 解析 token/行 -> 构造数据 -> 调用算法 -> 格式化输出
输入输出不是算法的附属细节。很多“看懂题但写不出来”的原因,其实是不知道怎样把题面数据变成 Python 对象。
先分清两种模式
核心代码模式
def two_sum(nums, target):
# nums 和 target 已经构造好
...
return answer
ACM 模式
import sys
def solve():
n, target = map(int, sys.stdin.buffer.readline().split())
nums = list(map(int, sys.stdin.buffer.readline().split()))
# 自己检查 nums 是否有 n 个元素
answer = ...
print(*answer)
if __name__ == "__main__":
solve()
ACM 程序必须自己读取、计算并打印,通常没有平台提供的函数参数。
input() 到底返回什么
input() 每次读取一行,去掉末尾换行,结果永远是字符串。
假设输入:
42
text = input() # "42",类型是 str
number = int(text) # 42,类型是 int
直接写 input() + 1 会触发 TypeError,因为字符串不能和整数相加。
split:把一行拆成多个字段
假设输入:
10 20 30
parts = input().split() # ["10", "20", "30"]
numbers = list(map(int, parts)) # [10, 20, 30]
split() 不传参数时会按任意连续空白分隔,自动处理多个空格和行首行尾空格。通常不要写 split(" ")。
一行一个整数
n = int(input())
一行多个整数
n, m = map(int, input().split())
左右变量数量必须与输入字段数量相同。
一行数组
nums = list(map(int, input().split()))
map 是惰性迭代器;需要下标、长度或多次遍历时转成 list。
字符串
s = input() # 保留内部空格
s = input().strip() # 额外去掉两端空白
characters = list(s) # 字符列表
如果空格本身是有效数据,不要随意 strip()。
读取 n 行
n 个整数,每行一个
n = int(input())
nums = [int(input()) for _ in range(n)]
n 行记录
输入:
3
alice 90
bob 85
carol 92
n = int(input())
records = []
for _ in range(n):
name, score_text = input().split()
records.append((name, int(score_text)))
矩阵与网格
整数矩阵
输入:
3 4
1 2 3 4
5 6 7 8
9 10 11 12
rows, cols = map(int, input().split())
matrix = [list(map(int, input().split())) for _ in range(rows)]
for row in matrix:
assert len(row) == cols
无空格字符网格
输入:
3 4
..#.
.#..
....
rows, cols = map(int, input().split())
grid = [list(input().strip()) for _ in range(rows)]
有空格字符或单词矩阵
grid = [input().split() for _ in range(rows)]
先看样例中元素之间有没有空格,再决定使用 list(input()) 还是 input().split()。
多组测试用例
第一行给 T
输入:
2
3
1 2 3
4
1 2 3 4
tests = int(input())
answers = []
for _ in range(tests):
n = int(input())
nums = list(map(int, input().split()))
answers.append(str(sum(nums[:n])))
print("\n".join(answers))
每组数据都要重新初始化局部状态,避免上一组的数组、计数器或 visited 泄漏到下一组。
读取到 EOF
有些题没有 T,要求读到文件结束:
import sys
for line in sys.stdin:
if not line.strip():
continue
a, b = map(int, line.split())
print(a + b)
不要用捕获所有异常的 while True 掩盖解析错误;按行遍历更清晰。
快速输入
input() 对一般题够用。数据很大时使用 sys.stdin.buffer。
readline:仍按行读取
import sys
input = sys.stdin.buffer.readline
n = int(input())
nums = list(map(int, input().split()))
这里读到的是 bytes,但 int(b"42") 可以直接转换。需要普通字符串时调用 decode():
name = input().decode().strip()
read:一次读取全部 token
import sys
tokens = sys.stdin.buffer.read().split()
numbers = list(map(int, tokens))
适合输入全部由空白分隔、无需保留行结构的题目。
token 指针解析模板
一次读完后,用指针按题面顺序消费 token:
import sys
def solve():
data = sys.stdin.buffer.read().split()
index = 0
n = int(data[index])
index += 1
nums = list(map(int, data[index:index + n]))
index += n
m = int(data[index])
index += 1
edges = []
for _ in range(m):
u = int(data[index])
v = int(data[index + 1])
index += 2
edges.append((u, v))
print(sum(nums), len(edges))
if __name__ == "__main__":
solve()
每解析一个字段就推进指针。复杂输入建议使用有意义的变量,不要把所有逻辑塞进一行。
输出语法
输出多个值
print(a, b, c) # 默认用空格分隔
print(a, b, c, sep=",") # 用逗号分隔
print(value, end=" ") # 末尾不换行
输出数组
answer = [1, 2, 3]
print(*answer) # 1 2 3
print(" ".join(map(str, answer)))
print(*answer) 简洁;大量输出时先拼字符串效率更稳定。
输出矩阵
for row in matrix:
print(*row)
批量输出
answers = []
for case in cases:
answers.append(str(solve_case(case)))
sys.stdout.write("\n".join(answers))
答案通常不应包含“结果是:”等额外说明。
浮点数输出
value = 1 / 3
print(f"{value:.2f}") # 0.33
print(f"{value:.6f}") # 0.333333
先确认题面要求保留位数、绝对误差还是相对误差。
一个完整 ACM 示例
题意:给定 n 个整数,输出最大值、最小值和总和。
输入:
5
3 1 4 1 5
代码:
import sys
def solve():
data = list(map(int, sys.stdin.buffer.read().split()))
if not data:
return
n = data[0]
nums = data[1:1 + n]
maximum = max(nums)
minimum = min(nums)
total = sum(nums)
print(maximum, minimum, total)
if __name__ == "__main__":
solve()
这段程序的边界职责很明确:
solve外只负责启动。- 开头负责解析。
- 中间负责算法。
- 末尾负责输出。
高频输入结构速查
| 题面格式 | 读取方式 |
|---|---|
| 单整数 | n = int(input()) |
| 一行整数 | a, b = map(int, input().split()) |
| 一行数组 | nums = list(map(int, input().split())) |
| n 行数组 | [list(map(int, input().split())) for _ in range(n)] |
| 无空格网格 | [list(input().strip()) for _ in range(n)] |
| T 组数据 | for _ in range(int(input())) |
| 直到 EOF | for line in sys.stdin |
| 超大 token 输入 | sys.stdin.buffer.read().split() |
常见错误
| 现象 | 原因 |
|---|---|
| ValueError: invalid literal for int | 读到了空字符串或非数字 |
| not enough values to unpack | 变量数量多于本行字段 |
| 输入明明有数据却读不到 | 多读了一行,或混用 read 与 readline |
| 输出 WA 但数值正确 | 多余文字、空格、换行或顺序错误 |
| T 组数据后答案互相影响 | 状态没有在每组重新初始化 |
| 大输入超时 | 逐行 input 过慢或频繁 print |
推荐的解题顺序
- 只根据题面写出输入结构注释。
- 用样例验证解析后的 Python 对象。
- 单独写算法函数并测试。
- 把算法接回
solve()。 - 最后严格按格式输出。
不要一边猜输入一边写算法;先确保“读对了”。
自测
- 读取 n 个学生的姓名和成绩,按成绩降序输出。
- 读取一个字符网格,统计字符
#的数量。 - 读取 T 组数组,分别输出每组最大子段和。
- 使用 token 指针读取 n 个点和 m 条边。
| ← 返回 Python 基础 | 上一篇:刷题工具与调试 | 下一章:数据结构 → |