首页
/ LeetCode-Go 题解 566:Reshape the Matrix 矩阵重塑(MATLAB reshape 原理与 Go 实现剖析)

LeetCode-Go 题解 566:Reshape the Matrix 矩阵重塑(MATLAB reshape 原理与 Go 实现剖析)

2026-09-11 17:31:36作者:郦嵘贵Just

本文以 LeetCode-Go 仓库中 0566.Reshape-the-Matrix 题解目录 为核心,完整讲解 LeetCode 第 566 题「重塑矩阵」的题目背景、判定条件与模拟填充思路,并逐行剖析该仓库的 Go 实现与测试用例。读完本文,你将掌握"元素总数守恒 + 行遍历填充"这一通用矩阵重塑范式,并能在不借助额外一维数组的情况下完成原地重排。

题目描述:MATLAB reshape 的二维数组版本

在 MATLAB 中,reshape 是一个非常有用的函数,它可以把一个矩阵重塑为大小不同但保留原始数据的新矩阵。LeetCode 566 题要求用二维数组实现同样的能力:

给出一个由二维数组表示的矩阵,以及两个正整数 rc,分别表示想要重构出的矩阵的行数和列数。重构后的矩阵需要将原始矩阵的所有元素**以相同的行遍历顺序(row-traversing order)**填充。如果该 reshape 操作可行且合法,则输出新的重塑矩阵;否则,输出原始矩阵。

通俗地说:把原矩阵按"先从左到右、再从上到下"的顺序读出所有元素,再按同样的顺序逐行填入新矩阵。关键在于,只有元素总数相等时重塑才合法

示例 1:展平成单行

Input:
nums =
[[1,2],
 [3,4]]
r = 1, c = 4
Output:
[[1,2,3,4]]

原矩阵的行遍历序列为 [1,2,3,4],将其逐行填入 1 × 4 的新矩阵即得到 [[1,2,3,4]]

示例 2:元素总数不匹配,返回原矩阵

Input:
nums =
[[1,2],
 [3,4]]
r = 2, c = 4
Output:
[[1,2],
 [3,4]]

2 × 2 = 4 个元素无法装进 2 × 4 = 8 个格子,重塑不合法,因此输出原矩阵。

数据范围说明

  1. 给定矩阵的高和宽均在 [1, 100] 范围内;
  2. 给定的 rc 均为正整数。

这意味着输入矩阵永不为空nums[0] 始终存在,后续代码可以直接取 len(nums[0]) 而无需判空,这是实现细节中的一个隐含前提。

核心解题思路:元素总数守恒 + 行遍历填充

这是一道典型的模拟(simulation)题,思路分两步:

  1. 合法性判定:设原矩阵为 m × n,目标矩阵为 r × c。只有当 m × n == r × c 时重塑才可行;
  2. 顺序填充:按行遍历原矩阵的每个元素,以相同的先后顺序逐行填入新矩阵。

只要抓住"原矩阵的行遍历顺序 = 新矩阵的填充顺序"这一等量关系,无论目标矩阵的形状如何变化,元素的相对顺序都不会被打乱。这也是 MATLAB reshape 在底层所遵循的基本语义。

Go 实现解析:仓库源码逐行剖析

LeetCode-Go 仓库在 566. Reshape the Matrix.go 中给出了完整实现,整体拆分为三个职责单一的函数:

func matrixReshape(nums [][]int, r int, c int) [][]int {
	if canReshape(nums, r, c) {
		return reshape(nums, r, c)
	}
	return nums
}

matrixReshape 是入口函数:先调用 canReshape 做合法性判定,可行则调用 reshape 执行重塑,否则原样返回 nums。这种"判定与执行分离"的写法让每个函数只做一件事,逻辑清晰、易于测试。

合法性判定:canReshape

func canReshape(nums [][]int, r, c int) bool {
	row := len(nums)
	colume := len(nums[0])
	if row*colume == r*c {
		return true
	}
	return false
}

判定条件就是元素总数守恒:len(nums) 得到原矩阵行数 mlen(nums[0]) 得到原矩阵列数 n,只有当 m*n == r*c 时返回 true。由于题目保证矩阵高宽在 [1, 100] 内、rc 均为正整数,这里不需要处理空矩阵或零尺寸的边界情况。

重塑填充:reshape

func reshape(nums [][]int, r, c int) [][]int {
	newShape := make([][]int, r)
	for index := range newShape {
		newShape[index] = make([]int, c)
	}
	rowIndex, colIndex := 0, 0
	for _, row := range nums {
		for _, col := range row {
			if colIndex == c {
				colIndex = 0
				rowIndex++
			}
			newShape[rowIndex][colIndex] = col
			colIndex++
		}
	}
	return newShape
}

填充阶段有两个关键点:

  1. 先分配再填充:先 maker 行,再为每一行 make 出长度为 c 的切片,得到完整的 r × c 零值矩阵;
  2. 用游标模拟行遍历:维护 rowIndexcolIndex 两个游标。每次写入一个元素后 colIndex++;当 colIndex == c 时说明当前行已写满,将 colIndex 归零、rowIndex++ 换到下一行。

由于 canReshape 已保证元素总数相等,双游标恰好会在填完最后一个元素时到达 (r, c) 的末尾,不存在越界或剩余元素的情况。这种写法无需借助额外的一维数组做中转,直接在目标矩阵上按位置落值,空间上更省。

注意:仓库源码中使用的变量名 columecolumn 的笔误,属于无伤大雅的命名瑕疵,不影响功能正确性。读者在自行实现时建议使用规范拼写 column

另一种等价实现:先展平后按行切片

除仓库的双游标方案外,另一种常见写法是先读取原矩阵的行遍历序列存入一维切片,再按每 c 个元素切分出一行。这种方案思路更直白("先读出来、再切回去"),但会额外占用 O(m×n) 的空间;仓库的双游标方案在空间上更优。两种方案的时间复杂度相同,读者可依据自己对可读性与空间开销的偏好选择。

复杂度分析

维度 复杂度 说明
时间复杂度 O(m×n) 需要遍历原矩阵的全部元素各一次,与重塑后的尺寸 r×c 相等
空间复杂度 O(r×c) 需要分配新矩阵存储结果;双游标方案无需额外的一维中转数组
非法情况 O(1) 元素总数不等时直接返回原矩阵,零拷贝

对于 m, n ≤ 100 的数据范围,最坏情况也只需处理 10,000 个元素,性能完全无压力,这也是 README 中将其称为"水题"的原因。

测试用例与验证

仓库在 566. Reshape the Matrix_test.go 中采用本仓库统一的"结构体参数化用例"风格组织测试,用 para566 封装输入参数(numsrc),用 ans566 封装期望输出:

qs := []question566{
    {para566{[][]int{{1, 2}, {3, 4}}, 1, 4}, ans566{[][]int{{1, 2, 3, 4}}}},
    {para566{[][]int{{1, 2}, {3, 4}}, 2, 4}, ans566{[][]int{{1, 2}, {3, 4}}}},
    {para566{[][]int{{1, 2, 3, 4}}, 2, 2}, ans566{[][]int{{1, 2}, {3, 4}}}},
}

三个用例覆盖了三种典型场景:

用例 输入 期望输出 验证点
用例 1 [[1,2],[3,4]], r=1, c=4 [[1,2,3,4]] 2×2 → 1×4 展平成功
用例 2 [[1,2],[3,4]], r=2, c=4 [[1,2],[3,4]] 元素总数不等(4≠8),返回原矩阵
用例 3 [[1,2,3,4]], r=2, c=2 [[1,2],[3,4]] 1×4 → 2×2 折叠成功

其中用例 3 恰好验证了"行遍历顺序"的正确性:虽然目标形状不同,但元素仍按 1,2,3,4 的顺序逐行落位,与示例 2 互为逆操作。用例 2 则单独验证了非法输入时原样返回的兜底逻辑。

运行方式上,可进入对应题解目录执行 go test 验证本用例,也可以使用仓库根目录的 gotest.sh 脚本对整个 leetcode 包做覆盖率测试:该脚本通过 go test -covermode=atomic -coverprofile=coverage.txt ./leetcode/... 一次性对多个包生成单一合法的覆盖率文件。仓库项目的 README 声称 100% test coverage,本题的测试结构正是这一质量标准的缩影。

边界情况与易错点总结

  1. 元素总数不匹配m×n != r×c 时必须返回原矩阵,这是最容易遗漏的分支,仓库通过 canReshape 单独抽出处理;
  2. 空矩阵:题目约束矩阵高宽在 [1, 100],所以实现中 len(nums[0]) 是安全的;若脱离本题约束自行扩展,需要先判断 len(nums) == 0
  3. 单行 / 单列互转:1×N 与 M×1 的互转(如用例 3)容易出错,验证时建议把这类"形状反转"用例加入测试;
  4. 填充游标的换行时机:写入元素之前判断 colIndex == c 还是之后判断,决定了游标复位逻辑的写法。仓库采用"写前判断、写后自增",读者可对比"写后判断"两种写法体会差异,避免出现列索引越界或漏换行的问题。

小结

LeetCode 566「重塑矩阵」的核心只有两件事:元素总数守恒是重塑合法的充要条件行遍历顺序是填充的唯一次序依据。LeetCode-Go 仓库用 matrixReshape / canReshape / reshape 三个函数将其拆解为"入口调度 + 可行性判定 + 游标填充",并以双游标方案免去一维中转数组,是一份兼顾可读性与空间效率的参考实现。若想进一步查看本题完整代码与测试,可继续阅读 题目文档、解法实现 与 测试文件。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.16 K
2.78 K
kernelkernel
deepin linux kernel
C
34
18
docsdocs
暂无描述
Markdown
904
5.83 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
932
1.86 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
862
1.36 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.95 K
1.03 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.38 K
1.47 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
535
606
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
549
398
leetcodeleetcode
🔥LeetCode solutions in any programming language | 多种编程语言实现 LeetCode、《剑指 Offer(第 2 版)》、《程序员面试金典(第 6 版)》题解
Markdown
77
23