
题目考点
这道题主要考这几个点:
- 输入处理
你要把多行输入,读成一个二维数组。 - 二维数组的理解
题目给的是 N 行 M 列,本质上就是“列表里面放列表”。 - NumPy 的基本操作
这道题不是让你手写转置,而是使用 NumPy 做:- transpose(转置)
- flatten(展平)
所以这道题的真正难点,往往不是 transpose() 和 flatten(),而是前面的这一步:
怎么把输入的数据,正确地读成一个二维数组。
审题
题目给你的是一个 N × M 的整数矩阵。
输入格式是这样的:
第一行:N M
接下来 N 行:每行有 M 个整数
比如样例输入:
2 2
1 2
3 4
它表示:
- 有 2 行
- 每行 2 个数
所以这个矩阵其实就是:
[
[1, 2],
[3, 4]
]
题目要求输出两部分:
- 先输出转置后的数组
- 再输出展平后的数组
思路提示
先不要急着记代码,先把过程想清楚。
这道题可以拆成 3 步:
第一步,先读入第一行,拿到 N 和 M。
第二步,再读接下来的 N 行,把每一行变成一个列表,最后组成“列表套列表”的二维数组。
第三步,把这个二维数组转成 NumPy 数组,然后调用:
numpy.transpose()numpy.flatten()
这里最关键的是第二步。
因为 input() 每次读进来的,其实都是一整行字符串。
比如读到这一行:
1 2
实际上最开始它是字符串 "1 2",不是列表,也不是整数。
所以你要经过:
input().split()
变成:
['1', '2']
再经过:
map(int, ...)
把每个字符串变成整数:
[1, 2]
这样一行一行处理后,最后就得到二维数组。
完整设计思路
第一步:读取行数和列数
第一行输入是:
N M
所以我们可以这样写:
N, M = map(int, input().split())
这句的意思是:
input()读入一整行,例如"2 2"split()按空格切开,得到['2', '2']map(int, ...)把两个字符串变成整数- 最后分别赋值给
N和M
这样:
N = 2
M = 2
第二步:读取矩阵
接下来有 N 行,每一行都是矩阵的一行。
所以我们需要循环 N 次,每次读一行:
arr = []
for _ in range(N):
row = list(map(int, input().split()))
arr.append(row)
这里的 arr 一开始是空列表。
假设输入是:
1 2
3 4
那么过程是:
第一次循环后:
arr = [[1, 2]]
第二次循环后:
arr = [[1, 2], [3, 4]]
这时候,它就已经是一个标准的二维数组结构了。
第三步:转成 NumPy 数组
上面的 arr 还是 Python 的普通列表。
而题目要用 NumPy 来做转置和展平,所以要先转成 NumPy 数组:
import numpy
arr = numpy.array(arr)
此时:
arr
就变成了 NumPy 的二维数组。
第四步:输出转置和展平
转置:
print(numpy.transpose(arr))
或者也可以写:
print(arr.transpose())
展平:
print(arr.flatten())
代码实现
下面给你一个适合初学者理解的完整版本:
import numpy
N, M = map(int, input().split())
arr = []
for _ in range(N):
row = list(map(int, input().split()))
arr.append(row)
arr = numpy.array(arr)
print(numpy.transpose(arr))
print(arr.flatten())
运行演示
我们用题目的样例来手动走一遍。
输入:
2 2
1 2
3 4
第一步:读第一行
N, M = map(int, input().split())
读到:
N = 2
M = 2
第二步:读矩阵
一开始:
arr = []
第一次循环读到:
1 2
处理后:
row = [1, 2]
arr = [[1, 2]]
第二次循环读到:
3 4
处理后:
row = [3, 4]
arr = [[1, 2], [3, 4]]
第三步:转成 NumPy 数组
arr = numpy.array(arr)
现在相当于:
[[1 2]
[3 4]]
第四步:转置
原矩阵是:
[[1 2]
[3 4]]
转置后,行列互换:
[[1 3]
[2 4]]
第五步:展平
展平就是把二维数组按顺序拉成一维:
[1 2 3 4]
最关心的问题:到底怎么“接受这个数组”?
这个问题非常关键。可以把“接受数组”理解成:
把输入的多行数字,存进程序里的变量。
这道题的接收方式就是:
接收一行数字
row = list(map(int, input().split()))
比如输入:
1 2 3
执行后:
row = [1, 2, 3]
接收整个二维数组
arr = []
for _ in range(N):
row = list(map(int, input().split()))
arr.append(row)
比如输入:
1 2
3 4
最后:
arr = [
[1, 2],
[3, 4]
]
所以可以记住这个固定模板:
arr = []
for _ in range(N):
row = list(map(int, input().split()))
arr.append(row)
以后遇到“输入一个矩阵”“输入一个二维数组”的题,十有八九都可以先想到这个模板。
再补一个理解点:为什么不是直接 input() 就行?
因为 input() 读到的是字符串。
例如输入:
1 2
你直接写:
x = input()
print(x)
print(type(x))
得到的是:
1 2
<class 'str'>
这说明它只是一个字符串,不是列表,也不是整数。
所以必须进一步处理:
split()
把字符串按空格切开:
input().split()
结果:
['1', '2']
注意,这仍然是字符串列表。
map(int, ...)
把每个字符串转成整数:
map(int, ['1', '2'])
再用 list() 变成列表:
[1, 2]
所以:
list(map(int, input().split()))
就是读一行整数最常见、最重要的写法之一。
方法总结
以后你看到这种题,判断方法可以很固定:
如果题目输入是“单行多个数”
就优先想到:
list(map(int, input().split()))
如果题目输入是“矩阵 / 二维数组 / N 行 M 列”
就优先想到:
arr = []
for _ in range(N):
row = list(map(int, input().split()))
arr.append(row)
如果题目还要求 NumPy 操作
再补一步:
arr = numpy.array(arr)
这就是这类题最核心的套路。
本节小结
这道题本身不难,真正要掌握的是“输入如何存成二维数组”。
你需要记住两层结构:
第一层,一行数字怎么读:
row = list(map(int, input().split()))
第二层,多行组成二维数组怎么读:
arr = []
for _ in range(N):
row = list(map(int, input().split()))
arr.append(row)
当你把这一步掌握了,后面的 transpose() 和 flatten() 就只是工具调用了。
练习
你先做这一题,不看答案,自己练一下输入接收。
题目:
输入一个 3 × 2 的整数矩阵,输出它原本的二维列表结构。
样例输入:
3 2
1 2
3 4
5 6
你只需要输出:
[[1, 2], [3, 4], [5, 6]]
提示:
- 第一行先读出
N和M - 用循环读
N次 - 每次把一行变成整数列表
- 用
append()放进总列表里
row = list(map(int, input().split()))这句代码到底在做什么
我们先把整句放出来:
row = list(map(int, input().split()))
这句代码的作用只有一句话:
把用户输入的一行数字,按空格拆开,并把每个数字从字符串变成整数,最后存成一个列表。
比如用户输入:
1 2 3 4
执行完这句后,row 就会变成:
[1, 2, 3, 4]
注意,最后得到的是一个“整数列表”,不是字符串,也不是一个大字符串。
先看结果,再反推过程
很多初学者一看到这句会觉得太长。
其实它只是把 4 个小动作连在了一起。
你可以把它拆成这样看:
temp1 = input()
temp2 = temp1.split()
temp3 = map(int, temp2)
row = list(temp3)
这 4 步合起来,才是原来那一句。
所以你真正要理解的,就是这 4 步分别做了什么。
第一步:input() 做了什么
作用
input() 会读取用户输入的一整行内容。
比如你运行程序,用户输入:
1 2 3 4
那么:
temp1 = input()
此时 temp1 的值是:
'1 2 3 4'
注意这里最关键的一点:
input() 读进来的永远是字符串 str。
哪怕你输入的是数字,它读进来以后仍然是字符串。
比如:
x = input()
print(x)
print(type(x))
如果你输入:
123
输出会是:
123
<class 'str'>
所以你要先牢牢记住:
input() 不会自动帮你变成整数。
第二步:split() 做了什么
我们继续看:
temp2 = temp1.split()
假设:
temp1 = '1 2 3 4'
那么执行后:
temp2 = ['1', '2', '3', '4']
split() 的本质
split() 的作用是:
把一个字符串按某种分隔方式切开,变成列表。
默认情况下,不写参数时,它按“空白字符”切分。
空白字符包括:
- 空格
- 制表符
- 换行等
所以:
'1 2 3 4'.split()
结果是:
['1', '2', '3', '4']
注意一个非常容易忽略的点
现在虽然已经变成列表了,但里面的元素还是字符串,不是整数。
也就是说:
['1', '2', '3', '4']
不是:
[1, 2, 3, 4]
你可以验证一下:
data = input().split()
print(data)
print(type(data))
print(type(data[0]))
如果输入:
1 2 3
那么:
data是列表listdata[0]是字符串str
所以 split() 只是“切开”,不负责类型转换。
第三步:map(int, temp2) 做了什么
这是很多初学者最容易卡住的一步。
temp3 = map(int, temp2)
假设:
temp2 = ['1', '2', '3', '4']
那么这句的意思是:
把 temp2 里面的每一个元素,都拿去执行一次 int()。
也就是相当于:
int('1')
int('2')
int('3')
int('4')
结果就会变成整数:
1, 2, 3, 4
你可以把 map 理解成“批量处理”
它的格式是:
map(函数, 可迭代对象)
这里:
- 函数是
int - 可迭代对象是
['1', '2', '3', '4']
所以它的意思就是:
把列表中的每个字符串,都交给 int 去处理。
第四步:list(...) 做了什么
在 Python 3 里,map() 返回的不是最终列表,而是一个 map 对象。
所以如果你直接写:
temp3 = map(int, ['1', '2', '3'])
print(temp3)
你看到的可能是这种结果:
<map object at 0x...>
这不是我们想要的最终数据。
所以要再套一层 list():
row = list(temp3)
这样才真正得到:
[1, 2, 3]
所以 list() 的作用就是:
把 map 处理后的结果,真正收集成一个列表。
从里到外,完整执行顺序
现在我们把原句重新看一遍:
row = list(map(int, input().split()))
它不是从左到右先执行 list,而是从里面往外执行。
实际顺序是:
第 1 层:先执行 input()
用户输入:
10 20 30
得到:
'10 20 30'
第 2 层:再执行 .split()
['10', '20', '30']
第 3 层:再执行 map(int, ...)
把每个字符串变成整数:
10, 20, 30
第 4 层:最后执行 list(...)
得到最终结果:
[10, 20, 30]
赋值给:
row
所以最后:
row = [10, 20, 30]
用一个完整例子手动模拟
下面我们手动模拟一遍,非常重要。
代码:
row = list(map(int, input().split()))
print(row)
print(type(row))
print(type(row[0]))
假设输入:
7 8 9
第一步
input()
读到的是:
'7 8 9'
类型是:
str
第二步
input().split()
得到:
['7', '8', '9']
类型是:
list
但里面每个元素的类型仍然是:
str
第三步
map(int, ['7', '8', '9'])
相当于:
int('7'), int('8'), int('9')
结果是:
7, 8, 9
第四步
list(...)
得到:
[7, 8, 9]
所以输出是:
[7, 8, 9]
<class 'list'>
<class 'int'>
为什么要这样写,不能直接用 input() 吗
不能,因为 input() 只会给你一整行字符串。
比如你想得到:
[1, 2, 3]
但你直接写:
row = input()
用户输入:
1 2 3
那么 row 得到的是:
'1 2 3'
它只是一个字符串。
这时你不能把它当成数字列表来用。
比如:
row[0]
得到的是字符 '1',不是整数 1。
如果输入是:
12 34 56
那 row[0] 得到的是字符 '1',更能看出问题。
所以必须经过:
split()切成多个部分int()把每部分转成整数list()收集成列表
这句代码的等价写法
如果你觉得原写法太紧凑,可以先写成更容易看懂的版本:
line = input()
parts = line.split()
row = []
for x in parts:
row.append(int(x))
这和下面这句是一个意思:
row = list(map(int, input().split()))
所以你可以这样理解:
简写版
row = list(map(int, input().split()))
展开版
line = input()
parts = line.split()
row = []
for x in parts:
row.append(int(x))
对于初学者来说,先理解展开版,再回头看简写版,会轻松很多。
再进一步:为什么 map(int, ...) 可以这样写
这里有一个很重要的语法思想:
map(函数, 数据)
它表示:
把“函数”应用到“数据”的每一个元素上。
例如:
例 1:把字符串变整数
list(map(int, ['1', '2', '3']))
结果:
[1, 2, 3]
例 2:把字符串变浮点数
list(map(float, ['1.5', '2.8', '3']))
结果:
[1.5, 2.8, 3.0]
例 3:把整数变字符串
list(map(str, [1, 2, 3]))
结果:
['1', '2', '3']
所以 map 并不是只会配合 int,它是一个“批量套函数”的工具。
常见错误
错误 1:忘了 split()
错误写法:
row = list(map(int, input()))
假设输入:
12 34 56
这里 input() 返回的是字符串 "12 34 56"。
如果直接对这个字符串做 map(int, ...),它会按字符一个一个处理,相当于在做:
int('1')
int('2')
int(' ')
int('3')
int('4')
...
一遇到空格就会报错。
所以必须先 split()。
错误 2:只 split(),不转整数
错误写法:
row = input().split()
结果是:
['1', '2', '3']
它看起来很像数字列表,但其实不是。
这会导致很多逻辑错误,比如:
row[0] + row[1]
不是数字相加,而是字符串拼接。
例如:
'1' + '2' -> '12'
这和你想要的 3 完全不同。
错误 3:忘了套 list()
错误写法:
row = map(int, input().split())
print(row)
你看到的不会是普通列表,而是一个 map 对象。
虽然它不是完全不能用,但对初学者来说不直观。
在做题时,通常直接套 list() 最清楚。
这句模板在题目里怎么用
情况 1:读一行整数
比如输入:
1 2 3 4 5
写法:
row = list(map(int, input().split()))
结果:
[1, 2, 3, 4, 5]
情况 2:读一行浮点数
比如输入:
88.5 90.0 76.5
写法:
scores = list(map(float, input().split()))
结果:
[88.5, 90.0, 76.5]
情况 3:读矩阵中的一行
比如矩阵有 N 行,每行都是整数:
arr = []
for _ in range(N):
row = list(map(int, input().split()))
arr.append(row)
这里的 row 就是矩阵的一行。
你可以怎样判断自己是不是真的懂了
你现在可以自己问自己这 4 个问题:
问题 1
input() 返回什么类型?
答案应该是:str
问题 2
split() 之后得到什么?
答案应该是:字符串列表
问题 3
map(int, ...) 在干什么?
答案应该是:把列表里每个字符串都转成整数
问题 4
为什么最后还要 list()?
答案应该是:把 map 的结果真正变成列表
如果这 4 个问题你都能答清楚,这句模板你就已经基本掌握了。
方法总结
把这句代码彻底压缩成一句最核心的话就是:
row = list(map(int, input().split()))
等于:
读一行 → 按空格切开 → 每个元素转成整数 → 收集成列表
你以后遇到“输入一行多个整数”的题,几乎都可以先想到这句。
你可以把它记成固定模板:
输入一行整数
row = list(map(int, input().split()))
输入一行浮点数
row = list(map(float, input().split()))
输入矩阵
arr = []
for _ in range(N):
row = list(map(int, input().split()))
arr.append(row)
本节小结
初学者最容易把这句看成一个整体,然后觉得难。
其实你只要愿意拆开,它本质上只是 4 个小动作:
line = input() # 读入整行字符串
parts = line.split() # 按空格切开,得到字符串列表
nums = map(int, parts) # 每个字符串转成整数
row = list(nums) # 变成真正的整数列表
所以以后遇到这种写法,不要害怕,第一反应就是:
从里往外拆。
练习
先自己做这道小练习,不要急着看答案。
题目:
用户输入一行数据:
10 20 30 40
请把它读成整数列表,然后输出:
[10, 20, 30, 40]
提示:
- 先用
input()读一整行 - 用
split()切开 - 用
map(int, ...)转整数 - 用
list()变成列表
补充说明:本题里 m 能不能不赋值
可以先给你一个非常准确的结论:
本题里,m 可以“不参与后续逻辑”,但不能“完全不读”。
这是两个不同的概念,你一定要分清。
一、什么叫“可以不用 m”
像这道题,常见写法是:
n, m = map(int, input().split())
然后后面只写:
arr = []
for _ in range(n):
row = list(map(int, input().split()))
arr.append(row)
你会发现:
n用来控制读多少行m好像没有继续写进代码里
所以从“后续逻辑是否依赖它”来说,这题里的 m 确实可以不用。
也就是说,你后面不一定非要写:
if len(row) != m:
也不一定非要写双重循环去用它。
二、什么叫“不能完全不读”
虽然 m 在后续逻辑中可以不用,但第一行输入里本来就有两个数:n 和 m。
比如输入:
2 2
1 2
3 4
第一行是:
2 2
这表示这一行里有两个值,不是一个值。
所以程序在读取第一行时,必须把这一行处理掉。
三、最容易混淆的点:不用 m,不等于不读取 m
这是你后续复习最容易疑惑的地方,我单独强调一下。
情况 1:读取了 m,但后面没使用
这是可以的。
例如:
n, m = map(int, input().split())
后面只用 n,不用 m。
这种写法完全没问题。
情况 2:第一行只想读 n,连 m 都不处理
这就要小心。
你不能直接写:
n = int(input())
因为第一行输入是:
2 2
而不是单独一个:
2
所以这句会报错。因为:
int("2 2")
这是不合法的。
四、所以到底能不能“只对 n 赋值”
能,但前提是:
你仍然要把第一行完整读进来,只是第二个值不保存,或者保存后不用。
这和“完全不读 m”不是一回事。
五、几种正确写法
写法 1:最推荐,最清楚
n, m = map(int, input().split())
优点是:
- 和题目格式完全对应
- 读代码的人一眼就知道输入是
n m - 后续即使暂时不用
m,也不影响理解
这也是最适合初学者、最适合复习的写法。
写法 2:明确表示“第二个值我读了,但不用”
n, _ = map(int, input().split())
这里的 _ 是一种约定俗成的写法,意思是:
这个值我接收了,但我不打算使用。
这就非常适合这种情况:
- 第一行确实有两个值
- 我必须把它们读出来
- 但后面逻辑只需要
n
这比直接硬省略更规范。
写法 3:手动取第一个值
first_line = input().split()
n = int(first_line[0])
这也能工作,因为:
input()已经把整行读走了split()已经把两个值都拆开了- 只是你只取了第一个
但这种写法不如前两种直观。
因为别人看代码时,会疑惑:
“题目明明有两个值,为什么只取一个?是不是漏了?”
所以这更适合你在特别明确的情况下使用,不适合作为初学者默认模板。
六、最不推荐的误解写法
错误理解:既然 m 没用,那我就当第一行只有一个数
比如有人会想写成:
n = int(input())
这在本题里不行。
因为第一行根本不是单独一个整数,而是两个整数在同一行。
样例第一行是:
2 2
不是:
2
所以这时候,不是“m 没用”,而是“输入格式已经规定这一行有两个值”。
程序必须按真实输入格式来读。
七、你可以这样理解:读取输入 和 使用变量 是两回事
这个区分特别重要。
第一步:读取输入
你要先保证程序把题目给的数据正确读进来。
题目说第一行有两个数,你就应该按两个数去读。
例如:
n, m = map(int, input().split())
或者:
n, _ = map(int, input().split())
第二步:使用变量
读进来之后,你再决定后面逻辑到底要不要用 m。
这题里通常只需要:
- 用
n控制循环次数 - 不额外用
m
所以是:
读了 m,但不一定要在后续逻辑中使用 m。
八、为什么本题里 m 常常可以不用
因为这道题的输入方式是“按行输入矩阵”。
你写的是:
for _ in range(n):
row = list(map(int, input().split()))
arr.append(row)
每次 input() 直接读一整行。
而平台保证每一行正好有 m 个元素,所以你不用自己再数一遍。
因此,m 在这题里更像是:
- 一个输入格式说明
- 一个维度信息
- 一个理论上可用于校验的值
而不是必须参与后续计算的核心变量。
九、那为什么很多标准答案还是会写 n, m
因为这样更完整、更规范。
原因有 3 个。
1. 和题目输入格式对应
题目第一行就是两个数。
你写:
n, m = map(int, input().split())
最符合题意。
2. 方便以后扩展
现在这题里 m 可能没用。
但如果以后题目要求你检查输入长度,或者用 reshape(n, m),那 m 就有用了。
保留它,代码扩展更自然。
3. 复习时不容易误会
如果你复习时只看到:
n, _ = map(int, input().split())
你还能知道原来第一行有两个值。
但如果你只写成某种非常简略的形式,后面再看就可能忘掉题目的完整输入结构。
所以从“适合长期复习”的角度说,保留 m 更稳妥。
十、这题到底推荐怎么写
如果你是为了学习、为了以后复习,我建议默认写成:
import numpy
n, m = map(int, input().split())
arr = []
for _ in range(n):
row = list(map(int, input().split()))
arr.append(row)
arr = numpy.array(arr)
print(numpy.transpose(arr))
print(arr.flatten())
这里虽然 m 没有被后续代码显式使用,但这份代码的优点是:
- 输入结构完整
- 可读性高
- 不容易让你以后误解“第一行到底有几个值”
十一、如果你就是想明确表示“m 不使用”,可以这样写
import numpy
n, _ = map(int, input().split())
arr = []
for _ in range(n):
row = list(map(int, input().split()))
arr.append(row)
arr = numpy.array(arr)
print(numpy.transpose(arr))
print(arr.flatten())
这也对。
但这里有两个 _:
- 第一个
_表示“第二个输入值我不使用” - 第二个
_表示“循环变量我不使用”
对初学者来说,两个 _ 放在一起有时会有点绕。
所以学习阶段我更建议你保留 m,更直观。
十二、一句话帮你彻底记住
你可以记这句:
本题里,m 可以不参与后续计算,但不能把它当作不存在。因为输入第一行本来就有它。
再压缩成更短一句:
可以“不用 m”,但不能“不读 m”。
本节小结
你这个问题非常值得单独补充,因为以后复习时确实很容易混淆。
这道题里:
n真正决定循环次数,因为要读n行m常常不参与后续逻辑,所以看起来“没用”- 但第一行输入格式是
n m - 所以程序必须把这两个值所在的那一行正确读出来
因此最规范的理解应该是:
m 在本题里可以是“读了但暂时不用”的变量,而不是“根本不存在的变量”。
练习
你自己先判断下面三种写法,哪种在本题里是合理的,哪种不合理。
写法 A
n, m = map(int, input().split())
写法 B
n, _ = map(int, input().split())
写法 C
n = int(input())
提示:
- 先想题目的第一行到底长什么样
- 再想“读取输入”和“后续是否使用”是不是一回事



