
本文详解如何通过智能翻转矩阵的行与列,使左上象限(前 n/2 行 × 前 n/2 列)元素和达到最大,并完整构造出对应的最优矩阵,避免暴力搜索,兼顾正确性与效率。
本文详解如何通过智能翻转矩阵的行与列,使左上象限(前 n/2 行 × 前 n/2 列)元素和达到最大,并完整构造出对应的最优矩阵,避免暴力搜索,兼顾正确性与效率。
在解决 HackerRank 等平台上的「矩阵游戏」类问题时,核心目标并非仅计算最大和,而是构造出达成该最大和的具体矩阵。题设允许任意次数地翻转任意行或列(即反转该行/列元素顺序),最终使大小为 ⌊n/2⌋ × ⌊n/2⌋ 的左上象限元素之和最大化。
关键洞察在于:每个位置 (i, j) 在行/列翻转操作下,并非独立变化,而是与三个对称位置构成一个封闭的四元组。对于 n×n 矩阵(通常为偶数阶,如 4×4、6×6),位置 (i, j) 可经以下操作相互抵达:
- 原位置:(i, j)
- 行翻转后:(n−1−i, j)
- 列翻转后:(i, n−1−j)
- 行+列翻转后:(n−1−i, n−1−j)
这四个位置构成一个轨道(orbit),且翻转操作只能在这四者之间置换元素,无法引入外部值。因此,要使左上象限(即 i ∈ [0, n/2), j ∈ [0, n/2))中每个 (i,j) 处的值尽可能大,最优策略是:对每个轨道,将其中的最大值“分配”到左上象限对应的位置 (i,j) 上,其余三个值则按需填入其对称位。
✅ 正确高效解法(贪心 + 轨道分解)
以下为时间复杂度 O(n²) 的最优实现(假设 n 为偶数):
public static int[][] matrixGameOptimal(int[][] arr) {
int n = arr.length;
int[][] result = new int[n][n];
// 遍历左上象限每个位置 (i, j)
for (int i = 0; i < n / 2; i++) {
for (int j = 0; j < n / 2; j++) {
// 获取该轨道的四个候选值
int[] candidates = {
arr[i][j],
arr[n - 1 - i][j],
arr[i][n - 1 - j],
arr[n - 1 - i][n - 1 - j]
};
// 找出最大值,并确定其原始位置
int maxVal = Integer.MIN_VALUE;
int maxIdx = 0;
for (int k = 0; k < 4; k++) {
if (candidates[k] > maxVal) {
maxVal = candidates[k];
maxIdx = k;
}
}
// 将最大值放在 (i, j),其余值填入对应对称位
// 使用映射:0→(i,j), 1→(n-1-i,j), 2→(i,n-1-j), 3→(n-1-i,n-1-j)
int[][] positions = {
{i, j},
{n - 1 - i, j},
{i, n - 1 - j},
{n - 1 - i, n - 1 - j}
};
// 先清空目标位置(避免重复赋值)
for (int k = 0; k < 4; k++) {
int r = positions[k][0], c = positions[k][1];
result[r][c] = candidates[k]; // 临时全填原值
}
// 将最大值移到 (i,j),并调整其余三值以保持轨道完整性
// 实际只需确保 (i,j) 是最大值;其余三个位置可任意排列(因翻转操作总能实现)
// 这里采用最简映射:把 maxVal 放 (i,j),其余按顺时针填充剩余三值
result[i][j] = maxVal;
// 构造剩余三值的轮换(例如:若 maxIdx=0,则其余为 [1,2,3];若 maxIdx=1,则原[0,2,3] → 放 (n-1-i,j) 处)
int[] rest = new int[3];
int restIdx = 0;
for (int k = 0; k < 4; k++) {
if (k != maxIdx) rest[restIdx++] = candidates[k];
}
// 按固定顺序填入其余三位置(保证可由合法翻转序列实现)
int[] order = {1, 2, 3}; // 对应 positions[1], positions[2], positions[3]
for (int k = 0; k < 3; k++) {
int r = positions[order[k]][0], c = positions[order[k]][1];
result[r][c] = rest[k];
}
}
}
return result;
}? 为什么此解法正确?
每个轨道的四个元素可通过至多两次翻转(一次行 + 一次列)任意排列。因此,对每个 (i,j) ∈ 左上象限,我们总能通过组合翻转,将轨道内最大值置于 (i,j),而其余值自然落于其对称位——无需模拟翻转过程,直接构造即可。
⚠️ 注意事项与常见误区
- 勿用贪心迭代翻转(如原代码中的 while 循环):它易陷入局部最优(例如先翻某行提升和,却阻塞后续更优列翻转),且无终止保证;复杂度不可控。
- 矩阵尺寸必须为偶数:题目隐含 n 为偶数(否则 n/2 非整数),若遇奇数尺寸,需明确象限定义(如 floor(n/2))。
- 深拷贝必要性:原代码中 arr[i].clone() 正确,但多次修改原数组会污染输入;推荐全程基于副本操作。
- 空间优化:上述实现已为 O(n²) 空间;若仅需返回最大和,可省略 result 数组,仅累加 maxVal。
✅ 总结
最大化左上象限和的本质,是对每个对称四元组独立选择最大值置入目标区域。该策略具备最优子结构性质,可严格证明其全局最优性。相比模拟翻转的启发式方法,轨道分解法简洁、高效、可验证,是此类对称翻转问题的标准解法。实际编码时,重点在于清晰识别等价类(轨道),并利用其置换自由度直接构造结果矩阵。

















