1895. 最大的幻方

123 阅读1分钟

题目:
一个 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
}