题目:
一个 k x k 的 幻方 指的是一个 k x k 填满整数的方格阵,且每一行、每一列以及两条对角线的和 全部 相等 。幻方中的整数 不需要互不相同 。显然,每个 1 x 1 的方格都是一个幻方。
给你一个 m x n 的整数矩阵 grid ,请你返回矩阵中 最大幻方 的 尺寸 (即边长 k)。
算法:
方法一:前缀和+模拟
func largestMagicSquare(grid [][]int) int {
n := len(grid)
m := len(grid[0])
// 同一行的前缀和
rowSum := make([][]int, n + 1)
// 同一列的前缀和
colSum := make([][]int, n + 1)
// 幻方左顶点开始的前缀和
leftDiagSum := make([][]int, n + 1)
// 幻方右顶点开始的前缀和
rightDiagSum := make([][]int, n + 1)
for i := 0; i <= n; i ++ {
rowSum[i] = make([]int, m + 1)
colSum[i] = make([]int, m + 1)
leftDiagSum[i] = make([]int, m + 1)
rightDiagSum[i] = make([]int, m + 1)
}
// 计算前缀和
for i := range grid {
for j, v := range grid[i] {
rowSum[i][j + 1] = rowSum[i][j] + v
colSum[i + 1][j] = colSum[i][j] +v
leftDiagSum[i + 1][j + 1] = leftDiagSum[i][j] + v
rightDiagSum[i + 1][j] = rightDiagSum[i][j + 1] + v
}
}
// 找最大的幻方
for k := min(n, m); k >= 1; k -- {
for r := k; r <= n; r ++ {
outer:
for c := k; c <= m; c ++ {
// 检查对角线的sum是否相等,不等则继续找
sum := leftDiagSum[r][c] - leftDiagSum[r - k][c - k]
if sum != rightDiagSum[r][c - k] - rightDiagSum[r - k][c] {
continue
}
// 检查rowSum
// 因为leftDiagSum[r][c]记录的其实是grid[r - 1][c - 1]的为左对角线最后顶点的坐标
// 而计算rowSum的时候,rowSum[i][j + 1] = rowSum[i][j] + v,是没有偏移的,
// 也就是说要取rowSum[r - 1]到rowSum[r - k]进行检查每一行的rowSum是否满足条件。
for i := r - 1; i >= r - k; i -- {
if rowSum[i][c] - rowSum[i][c - k] != sum {
continue outer
}
}
// 检查colSum
for j := c - 1; j >= c - k; j -- {
if colSum[r][j] - colSum[r - k][j] != sum {
continue outer
}
}
return k
}
}
}
return 1
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
}
func min(a, b int) int {
if a < b {
return a
}
return b
}