顺时针90°旋转后,(i,j)映射到(j,n−1−i);原地翻转需分层,每层四点循环交换,共⌊n/2⌋层。

顺时针90度翻转的坐标映射公式必须记牢
原矩阵中位置 (i, j)(0-indexed,i 行 j 列)在顺时针旋转90°后,会落到新矩阵的 (j, n - 1 - i) 位置。这个映射不是凭空来的——它本质是「先转置,再按行翻转」两步的合成结果。如果你直接手推 3×3 或 4×4 矩阵,很快就能验证:第 0 行变成最后一列,第 1 行变成倒数第二列……所以列索引 j 变成新行号,而原行号 i 决定新列号从底往上排,即 n - 1 - i。
常见错误是把映射写成 (n-1-j, i)(这是逆时针90°)或漏掉 -1 导致越界。调试时建议用 2×2 小矩阵手算一遍,比看公式更可靠。
原地翻转必须分层处理,不能逐行覆盖
若要求「原地」(in-place)操作、不额外分配 O(n²) 空间,就不能按行或按列顺序赋值——那样会提前覆盖还没读取的数据。正确做法是把矩阵看作嵌套的正方形环,对每一层(layer)做 4 个位置的循环交换:
- 左上 → 右上
- 右上 → 右下
- 右下 → 左下
- 左下 → 左上
对大小为 n 的方阵,总共有 n / 2 层(向下取整)。每层内,偏移量 offset 从 0 到 len - 1(其中 len = n - 2 * layer),对应该层每边的有效元素个数减一。代码里容易错的是边界条件:for (int layer = 0; layer 和内层 <code>for (int offset = 0; offset 缺一不可。
非方阵只能新建数组,别硬搞原地
如果输入是 m × n 矩阵(m != n),原地翻转根本不可行——因为旋转后尺寸变为 n × m,内存布局不兼容。此时必须分配新数组 vector<vector>>(n, vector<int>(m))</int></vector>,然后用坐标映射填值:
for (int i = 0; i <p>注意这里新矩阵行数是 <code>n</code>、列数是 <code>m</code>,而映射中的 <code>m - 1 - i</code> 是因为原矩阵有 <code>m</code> 行。混淆 <code>m</code> 和 <code>n</code> 是 runtime error 高发点,尤其当测试用例给的是 1×5 或 5×1 这种极端形状时。</p><h3> <code>std::swap</code> 在原地翻转中不是可选,是必需</h3><p>四个角交换时,如果用临时变量手动赋值,极易因顺序错误导致数据丢失。比如先写 <code>tmp = top</code>,再 <code>top = left</code>,再 <code>left = bottom</code>……中间一旦断掉,就全乱了。C++ 标准库的 <code>std::swap</code> 提供原子性保障,且针对内置类型通常编译为高效汇编指令。推荐写法是:</p><pre class="brush:php;toolbar:false;"> std::swap(matrix[layer][layer + offset], matrix[layer + offset][n - 1 - layer]); std::swap(matrix[layer + offset][n - 1 - layer], matrix[n - 1 - layer][n - 1 - layer - offset]); std::swap(matrix[n - 1 - layer][n - 1 - layer - offset], matrix[n - 1 - layer - offset][layer]);
最后一组交换完成后,四个位置才真正完成一轮闭环。少一次 std::swap,整个环就破了——而且这种 bug 很难通过肉眼检查发现,得靠打印中间状态或单元测试覆盖所有 layer/offset 组合。
最常被忽略的是:旋转算法对空矩阵(n == 0)或单行/单列(n == 1)必须能安全退出,否则 n / 2 或循环边界会出问题。实际写的时候,第一行就加个 if (matrix.empty() || matrix[0].empty()) return; 更省心。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











