【LeetCode 每日一题】1292. 元素和小于等于阈值的正方形的最大边长

Problem: 1292. 元素和小于等于阈值的正方形的最大边长

文章目录

  • [1. 整体思路](#1. 整体思路)
  • [2. 完整代码](#2. 完整代码)
  • [3. 时空复杂度](#3. 时空复杂度)
      • [时间复杂度: O ( M × N ) O(M \times N) O(M×N)](#时间复杂度: O ( M × N ) O(M \times N) O(M×N))
      • [空间复杂度: O ( M × N ) O(M \times N) O(M×N)](#空间复杂度: O ( M × N ) O(M \times N) O(M×N))

1. 整体思路

核心问题

在一个矩阵中,找到一个边长最大的正方形,使得该正方形内所有元素的和小于等于给定的 threshold。

算法逻辑

  1. 预处理:二维前缀和 (2D Prefix Sum)

    • 为了在 O ( 1 ) O(1) O(1) 时间内计算出任意子矩形(正方形)的元素和,代码首先构建了一个辅助数组 sum。
    • sum[i][j] 表示原矩阵中从 (0, 0) 到 (i-1, j-1) 矩形区域的元素总和。
    • 利用容斥原理公式:当前格前缀和 = 上 + 左 - 左上 + 当前元素值。
  2. 主逻辑:枚举位置 + 贪心扩展 (Smart Iteration)

    • 这也是这段代码最巧妙的地方。
    • 我们使用两个循环遍历矩阵的每个位置 (i, j),将其视为正方形的左上角。
    • 维护一个变量 ans,表示当前已经找到的最大边长。
    • 在遍历每个位置时,我们不需要 从边长 1 开始重新检查,也不需要二分查找边长。
    • 我们只需要检查:从当前位置 (i, j) 开始,能否形成一个边长为 ans + 1 的正方形,且其元素和 ≤ \le ≤ threshold?
      • 如果能 :说明我们找到了一个更大的正方形,于是执行 ans++。并在当前位置继续尝试 ans + 2(由 while 循环实现,尽管实际上每次位置移动通常最多增加 1,但在某些特殊情况下可能连续增加)。
      • 如果不能 :说明以当前 (i, j) 为起点的正方形无法打破当前的记录 ans,直接继续遍历下一个位置。
    • 这种策略保证了 ans 是单调递增的。我们只关心是否能找到比当前更大的正方形,忽略比当前小或相等的。

2. 完整代码

java 复制代码
class Solution {
    public int maxSideLength(int[][] mat, int threshold) {
        int m = mat.length;
        int n = mat[0].length;
        
        // 1. 构建二维前缀和数组
        // 大小设为 [m+1][n+1] 是为了方便处理边界(第0行和第0列全为0)
        int[][] sum = new int[m + 1][n + 1];
        
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                // 前缀和递推公式:上 + 左 - 左上 + 当前元素
                // 注意:sum 数组的索引比 mat 数组大 1
                sum[i + 1][j + 1] = sum[i + 1][j] + sum[i][j + 1] - sum[i][j] + mat[i][j];
            }
        }

        // ans 记录全局找到的最大边长
        int ans = 0;
        
        // 2. 遍历矩阵的每个格子,作为正方形的左上角
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                // 核心贪心逻辑:
                // 检查以 (i, j) 为左上角,边长为 ans + 1 的正方形是否合法。
                // 这里的 i + ans 其实对应的是边长 ans + 1 的右下角坐标偏移量。
                // 举例:若 ans=0,检查 i 到 i+0 (长度1);若 ans=1,检查 i 到 i+1 (长度2)。
                
                // 边界检查 (i + ans < m && j + ans < n) 确保正方形不越界
                // 阈值检查 (getRectSum(...) <= threshold) 确保元素和满足条件
                while (i + ans < m && j + ans < n && 
                       getRectSum(sum, i, j, i + ans, j + ans) <= threshold) {
                    // 如果满足条件,说明找到了一个更大的正方形 (边长 ans+1)
                    // 更新 ans,并尝试继续扩大(while 循环会继续检查 ans+2)
                    ans++;
                }
            }
        }
        return ans;
    }

    // 辅助方法:利用前缀和在 O(1) 时间内计算子矩形的元素和
    // (r1, c1) 是左上角, (r2, c2) 是右下角 (包含边界)
    private int getRectSum(int[][] sum, int r1, int c1, int r2, int c2) {
        // sum 数组中索引偏移了 1,所以右下角取 r2+1, c2+1
        // 左上角要减去的部分对应的索引是 r1, c1 (也就是原图索引 r1, c1 对应的 sum 数组位置)
        return sum[r2 + 1][c2 + 1] - sum[r2 + 1][c1] - sum[r1][c2 + 1] + sum[r1][c1];
    }
}

3. 时空复杂度

假设矩阵的行数为 M M M,列数为 N N N。

时间复杂度: O ( M × N ) O(M \times N) O(M×N)

  • 前缀和构建 :遍历整个矩阵一次,耗时 O ( M × N ) O(M \times N) O(M×N)。
  • 主循环与贪心检查 :
    • 虽然有双重 for 循环和一个内部的 while 循环,但我们可以这样分析:
    • 双重 for 循环会访问每个格子 (i, j) 一次。
    • 在每次访问时,getRectSum 的计算是 O ( 1 ) O(1) O(1) 的。
    • 关键在于 ans 变量。ans 在整个程序的生命周期中只增不减 。ans 的最大值也就限制在 min ⁡ ( M , N ) \min(M, N) min(M,N)。
    • 也就是说,while 循环中的 ans++ 操作总共最多执行 min ⁡ ( M , N ) \min(M, N) min(M,N) 次。
    • 大部分情况下,while 循环的条件判断只会执行一次(失败并退出)或者少数几次(成功并增加 ans)。
    • 因此,均摊下来,总操作次数与格子数量成正比。
  • 结论 : O ( M × N ) O(M \times N) O(M×N)。这是此问题的最优解法。

空间复杂度: O ( M × N ) O(M \times N) O(M×N)

  • 计算依据 :
    • 我们需要一个大小为 ( M + 1 ) × ( N + 1 ) (M+1) \times (N+1) (M+1)×(N+1) 的二维数组 sum 来存储前缀和。
  • 结论 : O ( M × N ) O(M \times N) O(M×N)。
相关推荐
糖果豆豆3 分钟前
灾难性遗忘不是"新旧打架"——旧知识记不住,是因为它没长成"环"
算法
垆边人似月.4 分钟前
华为题:任务调度
数据结构·c++·算法
垆边人似月.6 分钟前
华为题:编辑距离
算法·华为
会灭火的程序员6 分钟前
大模型部署硬件资源计算指南:从显存估算到显卡选型
人工智能·算法
信奥卷王14 分钟前
[GESP202506 六级] 最大因数(含视频)
数据结构·算法
局部有解20 分钟前
Leetcode - 42 接雨水(一维)
数据结构·c++·算法·leetcode
垆边人似月.26 分钟前
华为题:矩阵中的最长递增路径
算法·深度优先
小诗懂技术29 分钟前
linux驱动中断,相关中断的方式与适用场景
linux·arm开发·驱动开发·算法
不会就选b32 分钟前
算法日常・每日刷题--<动态规划>25
算法
Keep_Trying_Go41 分钟前
分割算法FastSAM论文详解
深度学习·算法·计算机视觉