package com.heu.wsq.leetcode.arr;
/**
* 1292. 元素和小于等于阈值的正方形的最大边长
* @author wsq
* @date 2021/4/6
* 给你一个大小为 m x n 的矩阵 mat 和一个整数阈值 threshold。
* 请你返回元素总和小于或等于阈值的正方形区域的最大边长;如果没有这样的正方形区域,则返回 0 。
*
* 示例 1:
*
* 输入:mat = [[1,1,3,2,4,3,2],[1,1,3,2,4,3,2],[1,1,3,2,4,3,2]], threshold = 4
* 输出:2
* 解释:总和小于或等于 4 的正方形的最大边长为 2,如图所示。
*
* 链接:https://leetcode-cn.com/problems/maximum-side-length-of-a-square-with-sum-less-than-or-equal-to-threshold
*/
public class MaxSideLength {
public int maxSideLength(int[][] mat, int threshold) {
int m = mat.length, n = mat[0].length;
int[][] f = new int[m + 1][n + 1];
// 求二维前缀和
for(int i = 1; i <= m; i++){
for(int j = 1; j <= n; j++){
f[i][j] = mat[i - 1][j - 1] + f[i - 1][j] + f[i][j - 1] - f[i - 1][j - 1];
}
}
int ans = 0;
// 由于要求的是正方形,所以需要求的目前矩阵mat中最小的边
int minEdge = Math.min(m, n);
// 逐个去试没一个k,效率偏低,可以使用二分查找进行优化
for(int k = 1; k <= minEdge; k++){
for(int i = 1; i <= m; i++){
for(int j = 1; j <= n; j++){
if(i - k < 0 || j - k < 0){
continue;
}
int tmp = f[i][j] - f[i-k][j] - f[i][j-k] + f[i-k][j-k];
if (tmp <= threshold){
ans = Math.max(ans, k);
}
}
}
}
return ans;
}
}