LeetCode 1878题解:矩阵菱形边界和优化计算

发布时间:2026/11/3 14:37:35
LeetCode 1878题解:矩阵菱形边界和优化计算

1. 问题背景与核心挑战

这道LeetCode 1878题要求我们在一个m×n的整数矩阵中,找出所有可能的"菱形"区域,并计算这些菱形边界元素的和,最终返回和最大的三个值(按降序排列)。这里的菱形特指将正方形旋转45度后形成的图形,且四个角必须位于矩阵网格点上。

举个例子,给定3×3矩阵:

[1,2,3] [4,5,6] [7,8,9]

其中边长为1的菱形和就是各个元素本身,边长为2的菱形和则是四个角的和(如1+3+7+9=20)。

1.1 菱形定义的关键约束

  1. 旋转特性:菱形必须是正方形旋转45度后的形态
  2. 边界计算:只计算菱形边界上的元素和,不包括内部元素
  3. 尺寸限制:菱形的边长不能超过矩阵的容纳范围
  4. 结果要求:返回最大的三个和,不足三个则全部返回

2. 暴力解法与复杂度分析

最直观的解法是枚举所有可能的菱形:

2.1 枚举所有菱形位置和尺寸

对于每个可能的中心点(i,j)和边长k:

  1. 检查是否能形成有效菱形
  2. 计算边界元素和
  3. 维护最大的三个和
def getBiggestThree(grid): m, n = len(grid), len(grid[0]) res = set() for i in range(m): for j in range(n): # 边长为0的菱形(单点) res.add(grid[i][j]) # 尝试不同边长 max_k = min(i, j, m-1-i, n-1-j) for k in range(1, max_k+1): total = 0 # 计算四条边 for d in range(k): total += grid[i-d][j+k-d] # 右上边 total += grid[i+k-d][j-d] # 右下边 total += grid[i+d][j-k+d] # 左下边 total += grid[i-k+d][j+d] # 左上边 res.add(total) res = sorted(res, reverse=True) return res[:3]

2.2 时间复杂度分析

假设矩阵尺寸为n×n:

  • 外层双重循环:O(n²)
  • 边长k循环:O(n)
  • 计算边界和:O(n) 总时间复杂度为O(n⁴),对于n=100的情况,这显然会超时。

3. 斜向前缀和优化

3.1 前缀和数组构建

我们构建两个斜向前缀和数组:

  1. 主对角线方向(左上到右下)
  2. 副对角线方向(右上到左下)
def buildPrefix(grid): m, n = len(grid), len(grid[0]) # 主对角线前缀和 diag1 = [[0]*(n+2) for _ in range(m+2)] # 副对角线前缀和 diag2 = [[0]*(n+2) for _ in range(m+2)] for i in range(1, m+1): for j in range(1, n+1): diag1[i][j] = diag1[i-1][j-1] + grid[i-1][j-1] diag2[i][j] = diag2[i-1][j+1] + grid[i-1][j-1] return diag1, diag2

3.2 利用前缀和快速计算菱形和

对于任意菱形,其四条边可以表示为四条斜边段的差值:

def calculateSum(diag1, diag2, i, j, k): # 将矩阵坐标转换为前缀和数组坐标(+1偏移) i += 1 j += 1 # 四个顶点的坐标 top = (i-k, j) right = (i, j+k) bottom = (i+k, j) left = (i, j-k) # 计算四条边的和 sum1 = diag2[top[0]][top[1]] - diag2[i][j-k] sum2 = diag1[right[0]][right[1]] - diag1[i][j+k] sum3 = diag2[bottom[0]][bottom[1]] - diag2[i][j+k] sum4 = diag1[left[0]][left[1]] - diag1[i][j-k] return sum1 + sum2 + sum3 + sum4

3.3 优化后的完整解法

def getBiggestThree(grid): m, n = len(grid), len(grid[0]) diag1, diag2 = buildPrefix(grid) res = set() for i in range(m): for j in range(n): res.add(grid[i][j]) max_k = min(i, j, m-1-i, n-1-j) for k in range(1, max_k+1): total = calculateSum(diag1, diag2, i, j, k) res.add(total) res = sorted(res, reverse=True) return res[:3]

4. 复杂度优化分析

使用斜向前缀和后:

  • 预处理时间:O(n²)
  • 查询每个菱形和:O(1)
  • 总时间复杂度:O(n³)

对于n=100的情况,计算量从10⁸降到10⁶,完全在合理范围内。

5. 边界条件与特殊测试用例

5.1 需要特别注意的情况

  1. 矩阵尺寸小于3×3时:

    • 1×1矩阵:只能形成边长为0的菱形
    • 2×2矩阵:只能形成边长为0和1的菱形
  2. 所有元素相同的情况:

    • 需要验证是否能正确返回三个相同的值
  3. 负数和零的情况:

    • 确保算法正确处理非正数

5.2 测试用例示例

test_cases = [ ([[1,2,3],[4,5,6],[7,8,9]], [20,9,8]), # 常规情况 ([[7,7,7]], [7]), # 单行矩阵 ([[1]], [1]), # 单元素矩阵 ([[6,9,8,1],[1,6,3,6],[5,5,6,1],[1,7,9,2]], [20,17,16]) # 复杂情况 ]

6. 算法优化技巧与心得

6.1 实现中的关键细节

  1. 前缀和数组的索引偏移:

    • 通常会在原始矩阵周围添加一圈0,避免边界判断
    • 在代码中表现为使用(m+2)×(n+2)的数组
  2. 菱形边长的计算:

    max_k = min(i, j, m-1-i, n-1-j)

    这个表达式确保菱形不会超出矩阵边界

  3. 使用集合去重:

    • 不同位置的菱形可能有相同的和
    • 使用集合自动处理重复值

6.2 性能优化建议

  1. 提前终止:

    • 当已经找到三个明显很大的和时,可以跳过一些小菱形的计算
  2. 并行计算:

    • 不同中心点的菱形计算相互独立,适合并行化
  3. 内存优化:

    • 可以只保留当前最大的三个和,而不是存储所有可能的值

7. 类似问题与扩展思考

7.1 LeetCode上的类似题目

    1. 二维区域和检索 - 矩阵不可变
    • 常规的前缀和应用
    1. 矩阵区域和
    • 滑动窗口与前缀和的结合
    1. 最大的以1为边界的正方形
    • 类似的结构处理思路

7.2 实际应用场景

  1. 图像处理中的菱形滤波器
  2. 游戏开发中的菱形地图处理
  3. 数据统计中的特殊区域分析

7.3 算法扩展方向

  1. 其他形状的区域和计算:

    • 三角形、六边形等
  2. 动态更新的矩阵:

    • 如何高效处理矩阵元素的实时更新
  3. 更高维度的扩展:

    • 三维空间中的类似问题