这个非常正常,而且是初学者最常见的问题之一。
很多人不是不会做题,而是看到这种:
N, M = map(int, input().split())
A = []
for _ in range(N):
A.append(list(map(int, input().split())))
脑子会断一下:
“这到底该怎么输入?”
“为什么要这么写?”
“我理解了,但下次还是记不住。”
你的问题不在于理解能力,而在于还没有把这种输入模式变成固定套路。
所以这一节我们就不急着讲题,而是专门把这段输入模板彻底讲透,让你以后看到类似题目就能自己写出来。
先解决一个最根本的问题:到底“怎么输入”?
你说“我不知道如何把它进行输入”,这里其实有两种场景。
第一种:在刷题平台上提交代码
比如 HackerRank、LeetCode、牛客之类的平台。
这种情况下,你不用在代码里写死数据,平台会自动把测试数据一行一行喂给你的 input()。
比如题目给的输入是:
2 3
1 2 3
4 5 6
那么程序执行时:
第一次 input() 读到的是:
"2 3"
第二次 input() 读到的是:
"1 2 3"
第三次 input() 读到的是:
"4 5 6"
也就是说,input() 每调用一次,就读一行。
第二种:你自己本地运行代码
如果你在本地运行,比如 VS Code、PyCharm、终端里跑 Python,那么程序运行到 input() 时,会停下来等你输入。
你就照题目样例,一行一行敲进去,比如:
2 3
1 2 3
4 5 6
每输完一行按一次回车。
所以你要记住一句非常关键的话:
input() 不是一次性把所有东西都读完,而是每次只读一整行。
先只记最核心的三句话
你现在先不要背整段代码,先只记这三句话:
第一句:input() 读一整行
比如输入:
2 3
那么:
input()
读到的是字符串:
"2 3"
注意,是字符串,不是数字。
第二句:.split() 按空格切开
input().split()
会把 "2 3" 变成:
["2", "3"]
它得到的是字符串列表。
第三句:map(int, ...) 把每个字符串变成整数
map(int, ["2", "3"])
会把每一项分别转成整数,变成相当于:
2, 3
所以:
N, M = map(int, input().split())
整体意思就是:
读一行 → 按空格切开 → 每项转成整数 → 分别给 N 和 M。
单独拆开讲:N, M = map(int, input().split())
我们把它拆成最笨、最容易懂的写法。
原写法
N, M = map(int, input().split())
拆开后其实相当于
line = input() # 读入一整行,比如 "2 3"
parts = line.split() # 变成 ["2", "3"]
numbers = map(int, parts) # 把 "2" 和 "3" 变成 2 和 3
N, M = numbers
如果再写得更适合初学者一点,可以想成:
line = input()
parts = line.split()
N = int(parts[0])
M = int(parts[1])
这两种写法本质是一回事。
所以你不是记不住它,而是你之前把它当成“一句神秘咒语”在记。
现在你要把它看成是 4 个小动作连在一起。
再拆第二段:为什么要这样读数组?
现在看这一段:
A = []
for _ in range(N):
A.append(list(map(int, input().split())))
你可以先不要整体看,先看它在做什么。
第一步:先准备一个空列表
A = []
意思是:我先准备一个地方,用来装整个二维数组。
你可以把 A 想成一个“总盒子”。
第二步:循环 N 次
for _ in range(N):
意思是:数组 A 有 N 行,所以我要读 N 次。
如果 N = 2,那就读两行。
如果 N = 3,那就读三行。
这里的 _ 只是表示“这个循环变量我不用”。
比如:
for _ in range(2):
就表示“做两次”。
第三步:每次读一行,并变成整数列表
list(map(int, input().split()))
比如这一行输入是:
1 2 3
那么它的变化过程是:
input() -> "1 2 3"
input().split() -> ["1", "2", "3"]
map(int, ...) -> 1, 2, 3
list(...) -> [1, 2, 3]
所以这一整句的作用就是:
把一行数字读成一个列表。
第四步:把这一行塞进 A 里面
A.append([1, 2, 3])
如果第一轮循环读到 [1, 2, 3],那 A 变成:
[[1, 2, 3]]
如果第二轮又读到 [4, 5, 6],那 A 变成:
[[1, 2, 3], [4, 5, 6]]
这就成了一个二维列表。
用一个完整例子手动模拟一遍
假设输入是:
2 3
1 2 3
4 5 6
现在一步一步来。
第 1 行输入
执行:
N, M = map(int, input().split())
读到:
"2 3"
切开后:
["2", "3"]
转整数后:
2, 3
所以:
N = 2
M = 3
初始化 A
A = []
现在:
A = []
第 1 次循环
执行:
A.append(list(map(int, input().split())))
读到第二行:
"1 2 3"
处理后变成:
[1, 2, 3]
追加后:
A = [[1, 2, 3]]
第 2 次循环
再执行一次:
A.append(list(map(int, input().split())))
读到第三行:
"4 5 6"
处理后变成:
[4, 5, 6]
追加后:
A = [[1, 2, 3], [4, 5, 6]]
到这里,二维数组就读完了。
你真正要记的,不是代码本身,而是“输入套路”
你现在不要死记这一长串代码,而是记下面这个套路。
模板 1:读一行多个整数
如果题目一行里有多个数字,比如:
2 3
你就用:
N, M = map(int, input().split())
你可以把它翻译成一句中文:
“读一行,用空格切开,转成整数,分别接住。”
模板 2:读 N 行数组
如果题目说“接下来有 N 行,每行若干个整数”,你就用:
A = []
for _ in range(N):
row = list(map(int, input().split()))
A.append(row)
翻译成中文就是:
“准备一个大列表,然后循环读 N 行,每行变成一个小列表,再塞进去。”
比起背代码,更推荐你记“句子版”
你以后写输入时,脑子里先默念这个:
读 N M
“先读第一行,拿到行数和列数。”
对应代码:
N, M = map(int, input().split())
读数组 A
“数组 A 有 N 行,所以循环 N 次;每次读一行整数,放进 A。”
对应代码:
A = []
for _ in range(N):
row = list(map(int, input().split()))
A.append(row)
你如果先能把这两句中文说出来,代码其实就比较容易跟着写出来。
为什么你会“理解,但记不住”?
因为你现在很可能是在记“长相”,不是记“动作”。
比如这句:
A.append(list(map(int, input().split())))
如果你把它当成一个整体去背,当然很难记。
但如果你把它拆成 4 个动作:
- 读一行
- 按空格切开
- 转成整数列表
- 追加到 A
那就容易多了。
所以以后不要背:
A.append(list(map(int, input().split())))
而是先想:
“我要读一行整数列表,然后放进 A。”
写不顺时,就拆开写:
row = list(map(int, input().split()))
A.append(row)
这比一口气写完整句更适合初学者。
初学者更推荐的写法
你完全可以先写成这种更清楚的版本:
N, M = map(int, input().split())
A = []
for _ in range(N):
row = input().split()
row = list(map(int, row))
A.append(row)
这个版本虽然多写了几行,但逻辑更清楚。
等你熟了,再压缩成:
A.append(list(map(int, input().split())))
这才是正常学习路径。
不是一开始就非得写得很短。
给你一个真正适合记忆的“万能输入骨架”
以后你看到这种二维数组题,可以先默写这个:
N, M = map(int, input().split())
A = []
for _ in range(N):
row = list(map(int, input().split()))
A.append(row)
你就把它理解成:
- 第一行:读规模
- 后面循环:一行一行读数据
这已经够用了。
如果还有第二个数组 B,那就再来一遍:
B = []
for _ in range(N):
row = list(map(int, input().split()))
B.append(row)
一个更实用的记忆法:按题目类型记模板
你以后做输入题,可以只分这 3 类。
第一类:只输入一个数
例如:
5
写法:
n = int(input())
第二类:一行输入多个数
例如:
2 3
写法:
N, M = map(int, input().split())
或者如果不确定有几个数:
nums = list(map(int, input().split()))
第三类:输入一个二维数组
例如后面还有 N 行:
1 2 3
4 5 6
写法:
A = []
for _ in range(N):
row = list(map(int, input().split()))
A.append(row)
你以后只要先判断题目属于哪一类,模板就容易拿出来了。
本节最重要的结论
你现在真正要掌握的,不是“把代码背下来”,而是这两个核心认知:
第一,input() 是一行一行读。
第二,二维数组的读取本质就是:循环读 N 行,每一行变成一个列表,再装进总列表。
只要这两点稳了,这类输入你就不会再特别怕。
你现在可以这样练,不要死背
建议你自己连续手写 3 遍下面这段,不看答案:
N, M = map(int, input().split())
A = []
for _ in range(N):
row = list(map(int, input().split()))
A.append(row)
每写一遍,都在旁边写中文解释:
- 读第一行,得到 N 和 M
- 建一个空列表 A
- 循环 N 次
- 每次读一行整数
- 把这一行加进 A
这样记得比单纯背代码牢很多。
方法总结
以后看到这类输入,不要慌,按这个顺序想:
第一步:题目让我读几次?
- 一次?
- N 次?
- 2N 次?
第二步:每次读的是一个数,还是一整行多个数?
- 一个数:
int(input()) - 多个数:
map(int, input().split())
第三步:最后我要存成什么?
- 单个变量
- 一维列表
- 二维列表
只要这三问能答出来,输入模板基本就能自己拼出来。
练习
你先做一个最小练习,不要急着看答案。
练习题
输入如下:
3 2
1 2
3 4
5 6
请你把它读成:
N = 3M = 2A = [[1, 2], [3, 4], [5, 6]]
提示
你只需要写输入部分,不用做后续计算。
先自己试着写:
- 第一行读
N, M - 建空列表
A - 循环
N次 - 每次读一行并追加到
A
不是不懂“为什么要这么做”,现在真正卡住的是:
input、split、map、int、list这几个东西到底谁先谁后append()到底是在哪一步加进去的- 这一串组合一长,就容易乱
这一步其实已经比“完全不会”进步很多了。因为你现在不是不会,而是顺序感不稳。
那这次我们就专门解决“顺序”问题。
先记一个最核心原则:看这种组合,要“从里往外”读
比如这句:
list(map(int, input().split()))
不要从左往右硬读。
这种嵌套结构,最稳的读法是:
先看最里面,再一层一层往外包。
就像剥洋葱一样。
把这句拆开:到底谁先执行?
我们来看:
list(map(int, input().split()))
执行顺序其实是这样的:
第 1 步:先执行 input()
input()
因为它在最里面。
作用:读入一整行字符串。
比如你输入:
1 2 3
那么:
input()
得到的是:
"1 2 3"
第 2 步:再执行 .split()
input().split()
作用:把这一整行按空格拆开。
所以:
"1 2 3".split()
得到:
["1", "2", "3"]
注意,这里还是字符串,不是整数。
第 3 步:再执行 map(int, ...)
map(int, input().split())
作用:把拆出来的每个字符串,逐个用 int() 转成整数。
也就是把:
["1", "2", "3"]
变成“相当于”:
1, 2, 3
这里你可以先把 map(int, ...) 暂时理解成:
“把里面的每一项都做一次 int 转换。”
第 4 步:最后执行 list(...)
list(map(int, input().split()))
作用:把前面那些转换好的整数,真正收集成一个列表。
所以最后结果就是:
[1, 2, 3]
所以这串组合的执行顺序是
不是你写出来的顺序,而是:
input()
→ split()
→ map(int, ...)
→ list(...)
你可以把它记成一句话:
先读,后切,再转,最后装。
这是最重要的一句记忆口诀。
给你一个特别适合记忆的顺口版
看到这句:
list(map(int, input().split()))
脑子里不要背代码,直接念中文:
读一行 → 切开 → 转整数 → 变列表
也就是:
input():读一行.split():切开map(int, ...):转整数list(...):装成列表
你以后只要先会说这句中文,代码就容易写出来。
单独讲:为什么 int 写在 map 里面?
很多初学者会看到这里有点懵:
map(int, input().split())
会想:“为什么不是 int(map(...))?为什么不是 split(int)?”
这里你要记住:
map(函数, 数据) 的意思是
把“函数”作用到“数据里的每一项”上。
比如:
map(int, ["1", "2", "3"])
意思就是:
- 对
"1"做int() - 对
"2"做int() - 对
"3"做int()
结果相当于得到:
1, 2, 3
所以:
int是“处理规则”input().split()是“要处理的数据”
这就是为什么 int 要放在 map 的第一个位置。
再单独讲:append() 到底是在什么时候做的?
你现在第二个容易乱的地方,就是这个:
A.append(list(map(int, input().split())))
你会觉得:
“到底是先 append,还是先 input?”
“append 在整个过程里是干嘛的?”
答案是:
先把右边整出来,再 append 到 A。
这句真正的顺序是这样
A.append(list(map(int, input().split())))
不要整体看,把它拆成两部分:
右边先算出来
list(map(int, input().split()))
这一部分先执行,最终会得到一个列表,比如:
[1, 2, 3]
然后再执行 append
有了这个结果后,才执行:
A.append([1, 2, 3])
也就是说:
append() 不是一边读一边加,它是等右边先准备好一个完整的小列表,再把这个小列表塞进 A。
所以 append 可以这样记
append(x) 的意思不是“处理数据”
它只是:
把已经准备好的东西 x,加到列表最后面。
比如:
A = []
A.append([1, 2, 3])
结果就是:
A = [[1, 2, 3]]
再来一次:
A.append([4, 5, 6])
结果变成:
A = [[1, 2, 3], [4, 5, 6]]
所以 append 本身很简单,它不负责切、转、读,它只负责:
加进去。
可以把整句分成“生产”和“存放”两部分
这一句:
A.append(list(map(int, input().split())))
可以记成两半:
前半部分:生产一行数据
list(map(int, input().split()))
作用:得到一行整数列表,比如 [1, 2, 3]
后半部分:把这行数据放进 A
A.append(...)
作用:把上面那一行塞进 A
对初学者来说,更推荐你先写成两句
如果你现在觉得一口气写成一大句容易乱,那就先写成两句。
推荐版
row = list(map(int, input().split()))
A.append(row)
这样顺序会清楚很多:
第一句:先读出一行
第二句:再追加进 A
这比直接写成一整句更适合你现在这个阶段。
我们手动模拟一遍完整过程
假设输入是:
1 2 3
现在执行:
row = list(map(int, input().split()))
A.append(row)
第一步:input()
读到:
"1 2 3"
第二步:.split()
变成:
["1", "2", "3"]
第三步:map(int, ...)
逐个转整数,得到相当于:
1, 2, 3
第四步:list(...)
变成:
[1, 2, 3]
于是:
row = [1, 2, 3]
第五步:A.append(row)
如果原来:
A = []
那么执行后:
A = [[1, 2, 3]]
这就是整个流程。
你现在要重点区分两类东西
这是最关键的区分。
第一类:处理输入内容的
这些是“把一行文字变成数字列表”的工具:
input().split()map(int, ...)list(...)
它们负责的是:加工数据
第二类:存数据的
这个是“把加工好的结果放进大列表”的工具:
append()
它负责的是:保存结果
所以完整逻辑其实就是一句话
先把这一行处理成列表,再 append 到总列表里。
这句话你一定要记住。
你可以这样强行拆解,帮助自己记忆
把:
A.append(list(map(int, input().split())))
拆成下面这样:
line = input() # 读一行
parts = line.split() # 切开
nums = map(int, parts) # 转整数
row = list(nums) # 变成列表
A.append(row) # 塞进 A
你会发现,一点都不神秘。
只是平时为了写得简洁,把它们压缩到一行里了。
记忆时,不要背“长代码”,要背“动作链”
你最该记住的不是字面,而是这个动作顺序:
一行数据的生成流程
读 → 切 → 转 → 装
对应:
input() → split() → map(int, ...) → list(...)
二维数组的存储流程
每次生成一行 → append 进总列表
对应:
row = ...
A.append(row)
给你一个真正实用的记忆口诀
对 list(map(int, input().split()))
记成:
读一行,切一刀,全转整,装成表。
对 A.append(row)
记成:
这一行已经弄好了,塞进 A 里。
这比死记代码更有用。
以后你实战时,建议先写“展开版”
在你还不够熟的时候,完全没必要直接写:
A.append(list(map(int, input().split())))
你可以先写展开版:
row = input().split()
row = list(map(int, row))
A.append(row)
甚至更展开:
line = input()
parts = line.split()
row = list(map(int, parts))
A.append(row)
这样最不容易错。
等你写熟了,再压缩。
方法总结
你现在这一步只需要死死抓住下面两点。
第一,嵌套表达式从里往外看
看到:
list(map(int, input().split()))
执行顺序是:
input()
→ split()
→ map(int, ...)
→ list()
不是从左往右机械读。
第二,append 永远是“最后放进去”
看到:
A.append(...)
就理解成:
先把括号里的内容算出来,再放进 A。
本节小结
你现在已经知道这类代码在干什么了,下一步就是建立“顺序感”。
把这两句话背熟就够了:
第一句:list(map(int, input().split())) = 读一行,切开,转整数,装成列表
第二句:A.append(row) = 把这一行加到 A 的最后面
这就是全部核心。
练习
这次给你一个很小的练习,只练顺序,不练题目。
练习题
请你自己不用看答案,试着把下面这句代码拆成 3 到 5 行:
A.append(list(map(int, input().split())))
要求你拆完之后,每一行旁边写中文注释,说明这一行在干什么。
提示
你可以按这个思路拆:
- 先读一行
- 再切开
- 再转整数列表
- 最后 append 到 A



