Given a m x n matrix mat and an integer threshold. Return the maximum side-length of a square with a sum less than or equal to threshold or return 0 if there is no such square.

Example 1:

Input: mat = [[1,1,3,2,4,3,2],[1,1,3,2,4,3,2],[1,1,3,2,4,3,2]], threshold = 4
Output: 2
Explanation: The maximum side length of square with sum less than 4 is 2 as shown.

Example 2:

Input: mat = [[2,2,2,2,2],[2,2,2,2,2],[2,2,2,2,2],[2,2,2,2,2],[2,2,2,2,2]], threshold = 1
Output: 0

Example 3:

Input: mat = [[1,1,1,1],[1,0,0,0],[1,0,0,0],[1,0,0,0]], threshold = 6
Output: 3

Example 4:

Input: mat = [[18,70],[61,1],[25,85],[14,40],[11,96],[97,96],[63,45]], threshold = 40184
Output: 2

Constraints:

  • 1 <= m, n <= 300
  • m == mat.length
  • n == mat[i].length
  • 0 <= mat[i][j] <= 10000
  • 0 <= threshold <= 10^5

输入一个二维数组mat和一个整数treshold.
二维数组代表一个矩形,对于其中的正方形,(正方形所包含的点的和值小于等于treshold),返回最大的那个正方形的边长。
方法1:暴力搜索。

// O(m*n*min(m,n))
public int maxSideLength(int[][] mat, int threshold) {
    int m = mat.length, n = mat[0].length;
    int[][] dp = new int[m + 1][n + 1];
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            dp[i][j] = dp[i][j - 1] + dp[i - 1][j] - dp[i - 1][j - 1] + mat[i - 1][j - 1];
        }
    }
    int ans = 0;
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            for (int k = 0; i + k <= m && j + k <= n; k++) {
                // 计算矩形面积
                int area = rangeSum(i, j, i + k, j + k, dp);
                if (area > threshold) break;
                ans = Math.max(ans, k + 1);
            }
        }
    }
    return ans;
}

// 求以[x1, y1]点为左上角,[x2, y2]点为右下角的矩形的面积
private int rangeSum(int x1, int y1, int x2, int y2, int[][] dp) {
    return dp[x2][y2] - dp[x2][y1 - 1] - dp[x1 - 1][y2] + dp[x1 - 1][y1 - 1];
}

把k初始化时,直接替换成ans,可以把时间复杂度降低为平方级。
image.png
再看binary search方法:

class Solution {
    // O(m*n*lg(min(m,n))
    public int maxSideLength(int[][] mat, int threshold) {
        int m = mat.length, n = mat[0].length;
        int[][] dp = new int[m + 1][n + 1];
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                dp[i][j] = dp[i][j - 1] + dp[i - 1][j] - dp[i - 1][j - 1] + mat[i - 1][j - 1];
            }
        }
        int ans = 0;
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                // 可以用binary search 把时间复杂度从m*n*min(m,n)降为m*n*lg(min(m,n))
                int left = 0, right = Math.min(m - i, n - j) + 1;
                while (left < right) {
                    int mid = left + (right - left) / 2;
                    if (rangeSum(i, j, i + mid, j + mid, dp) > threshold) {
                        right = mid;
                    } else {
                        left = mid + 1;
                    }
                }
                ans = Math.max(ans, left);
            }
        }
        return ans;
    }

    // 求以[x1, y1]点为左上角,[x2, y2]点为右下角的矩形的面积
    private int rangeSum(int x1, int y1, int x2, int y2, int[][] dp) {
        return dp[x2][y2] - dp[x2][y1 - 1] - dp[x1 - 1][y2] + dp[x1 - 1][y1 - 1];
    }
}
https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-1292-maximum-side-length-of-a-square-with-sum-less-than-or-equal-to-threshold/

proheart
41 声望20 粉丝

Developer, Java & Android