LeetCode——5202. 最大的幻方[Largest Magic Square][中等]——分析及代码[Java]
一、题目
一个 k x k 的 幻方 指的是一个 k x k 填满整数的方格阵,且每一行、每一列以及两条对角线的和 全部相等 。幻方中的整数 不需要互不相同 。显然,每个 1 x 1 的方格都是一个幻方。
给你一个 m x n 的整数矩阵 grid ,请你返回矩阵中 最大幻方 的 尺寸 (即边长 k)。
示例 1:
输入:grid = [[7,1,4,5,6],[2,5,1,6,4],[1,5,4,3,2],[1,2,7,3,4]]
输出:3
解释:最大幻方尺寸为 3 。
坐标(1,1)为左上角的正方形,每一行,每一列以及两条对角线的和都等于 12 。
- 每一行的和:5+1+6 = 5+4+3 = 2+7+3 = 12
- 每一列的和:5+5+2 = 1+4+7 = 6+3+3 = 12
- 对角线的和:5+4+3 = 6+4+2 = 12
示例 2:
输入:grid = [[5,1,3,1],[9,3,3,1],[1,3,3,8]]
输出:2
提示:
- m == grid.length
- n == grid[i].length
- 1 <= m, n <= 50
- 1 <= grid[i][j] <= 10^6
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/largest-magic-square
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
二、分析及代码
1. 前缀和 + 枚举
(1)思路
从大到小枚举所有正方形,判断是否为幻方。可通过预计算各行、列的前缀和,降低时间复杂度。
(2)代码
class Solution {
public int largestMagicSquare(int[][] grid) {
int m = grid.length, n = grid[0].length;
//计算各行、各列的前缀和
int[][] row = new int[m][n + 1], col = new int[m + 1][n];
Arrays.fill(col[0], 0);
for (int i = 0; i < m; i++) {
row[i][0] = 0;
for (int j = 0; j < n; j++) {
row[i][j + 1] = row[i][j] + grid[i][j];
col[i + 1][j] = col[i][j] + grid[i][j];
}
}
//从大到小枚举正方形
for (int len = Math.min(m, n); len > 1; len--) {//枚举边长
for (int i = 0; i + len <= m; i++) {//枚举起始点横坐标
for (int j = 0; j + len <= n; j++) {//枚举起始点纵坐标
boolean isMagic = true;
int sum = row[i][j + len] - row[i][j], dia1 = 0, dia2 = 0;//选取第一行的和作为标准计算
for (int k = 0; k < len; k++) {
if (row[i + k][j + len] - row[i + k][j] != sum || col[i + len][j + k] - col[i][j + k] != sum) {//计算各行、列和是否相等
isMagic = false;
break;
}
dia1 += grid[i + k][j + k];//计算对角线和
dia2 += grid[i + len - 1 - k][j + k];//计算另一对角线和
}
if (isMagic == true && dia1 == sum && dia2 == sum)//判断行、列及对角线和是否全部相等
return len;
}
}
}
return 1;//边长为1的方格一定是幻方
}
}
(3)结果
执行用时 :6 ms,在所有 Java 提交中击败了 100.00% 的用户;
内存消耗 :38 MB,在所有 Java 提交中击败了 100.00% 的用户。
(目前提交用户量不足,暂无排名)
三、其他
还可通过预计算对角线的前缀和,进一步简化算法。