元素和小于等于阈值的正方形的最大边长(来源:力扣(LeetCode))

给你一个大小为 m x n 的矩阵 mat 和一个整数阈值 threshold。请你返回元素总和小于或等于阈值的正方形区域的最大边长;如果没有这样的正方形区域,则返回 0 。来源:力扣(LeetCode)

示例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,如图所示。来源:力扣(LeetCode)

示例2:

输入: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
输出:0来源:力扣(LeetCode)

解法一:动态规划

这道题给了一个 m x n 的二维数组和一个整型数 threshold,让返回最大正方形的边长,使得正方形区间内的数字之和小于等于 threshold。像这种求二维数组子区间和的问题,可以很容易联想到一维数组的求子数组之和的问题,通过建立累加和数组可以快速的求出一维数组中任意区间的子数组之和。对于二维数组也是一样的道理,可以建立二维的累加和数组,然后遍历每一个正方形区间,通过累加和数组快速得到其数字之和,然后比较若小于等于 threshold,则用其边长来更新结果 res 即可。二维累加和数组的大小要比原数组大1,这样方便处理越界的问题,累加的方法就是当前位置对应的原数组的数字,加上累加数组上方和左边的数字,减去左上方的数字。

构建完成了累加和数组之后,就可以遍历所有的正方形区间了。由于只需要一个顶点和边长就可以唯一的确定一个正方形区间,所以可以遍历数组中的每一个位置,当作正方形区间的左上顶点,然后遍历所有不越界的边长,并快速求区间和。注意求区间和的方法和求累加和数组的方法是有一些区别的,当正方形区间的左上顶点为 (i, j),边长为 k+1 的时候,则右下顶点为 (i+k, j+k),区间和的计算方法是 sums[i + k][j + k] - sums[i - 1][j + k] - sums[i + k][j - 1] + sums[i - 1][j - 1],可以自行比较下和计算累加和数组的区别,然后就是和 threshold 比较了,若小于等于 threshold,则用 k+1 来更新结果 res 即可,参见代码如下:

package com.ice.blindweb;/* @Auther: sugarice* @Date: 2022/07/24/13:57* @Description:*/public class main {public static 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] = mat[i - 1][j - 1] + dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1];}}int ans = 0;for (int k = 1; k <= Math.min(m, n); 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 = dp[i][j] - dp[i - k][j] - dp[i][j - k] + dp[i - k][j - k];if (tmp <= threshold) {ans = Math.max(ans, k);}}}}return ans;}public static void main(String[] args) {//        示例 1int[][] mat = {{1, 1, 3, 2, 4, 3, 2}, {1, 1, 3, 2, 4, 3, 2}, {1, 1, 3, 2, 4, 3, 2}};int i = maxSideLength(mat, 4);System.out.println(i);//        示例 2int[][] mat1 = {{2, 2, 2, 2, 2, 2, 2}, {2, 2, 2, 2, 2, 2, 2}, {2, 2, 2, 2, 2, 2, 2}};int j = maxSideLength(mat1, 1);System.out.println(j);}
}

解法二:动态规划+二分查找

由于所求的最大边长是有范围的,最小为0,最大不超过m和n中的较小值,那么就可以用二分搜索法来增加查找的速度。还是需要建立累加和数组 sums,然后就可以开始二分搜索了,用子函数当作判断关系(通常由 mid 计算得出)。判断的子函数其实就是在整个数组中查找是否存在均有给定边长的正方形区间,使得其数字和小于等于 threshold。因为此时边长确定了,只要遍历左上顶点的位置,然后通过累加和数组快速计算出区间和进行判断即可,参见代码如下:

package com.ice.blindweb;/* @Auther: sugarice* @Date: 2022/07/24/14:22* @Description:*/public class main1 {private static int m, n;public static int maxSideLength(int[][] mat, int threshold) {m = mat.length;n = mat[0].length;int left = 0;int right = Math.min(m, n);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] = mat[i - 1][j - 1] + dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1];}}
//       二分查找while (left <= right) {int mid = left + (right - left) / 2;if (squareExisted(dp, threshold, mid)) {left = mid + 1;} else {right = mid - 1;}}return right;}public static Boolean squareExisted(int[][] sums, int threshold, int len) {for (int i = 1; i <= m; i++) {for (int j = 1; j <= n; j++) {if (i - len < 0 || j - len < 0) {continue;}int tmp = sums[i][j] - sums[i - len][j] - sums[i][j - len] + sums[i - len][j - len];if (tmp <= threshold) {return true;}}}return false;}public static void main(String[] args) {//        示例 1int[][] mat = {{1, 1, 3, 2, 4, 3, 2}, {1, 1, 3, 2, 4, 3, 2}, {1, 1, 3, 2, 4, 3, 2}};int i = maxSideLength(mat, 4);System.out.println(i);//        示例 2int[][] mat1 = {{2, 2, 2, 2, 2, 2, 2}, {2, 2, 2, 2, 2, 2, 2}, {2, 2, 2, 2, 2, 2, 2}};int j = maxSideLength(mat1, 1);System.out.println(j);}
}

解法三:一种更加高效的方法

这种方法在建立累加和的过程中就直接进行判断了,而且每次只判断是否有比当前已经存在的正方行边长大1的区间,有的话就让结果 res 自增1,因为左上顶点一次只能移动一个位置,不管是向右,还是向下移动,边长最多也只能增加1。这道题的难点还是在于计算区间时下标的转换,因为此时的正方形区间的右下顶点为 (i, j),左上顶点为 (i-res, j-res),计算区间和的方法为 sums[i][j] - sums[i - res - 1][j] - sums[i][j - res - 1] + sums[i - res - 1][j - res - 1],前提要保证 i - res - 1 和 j - res - 1 均大于等于0,以防止越界,参见代码如下:

package com.ice.blindweb;/* @Auther: sugarice* @Date: 2022/07/24/14:22* @Description:*/public class main2 {public static int maxSideLength(int[][] mat, int threshold) {int m = mat.length;int n = mat[0].length;int res = 0;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] = mat[i - 1][j - 1] + dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1];if (i - res - 1 >= 0 && j - res - 1 >= 0 && dp[i][j] - dp[i - res - 1][j] - dp[i][j - res - 1] + dp[i - res - 1][j - res - 1] <= threshold) {++res;}}}return res;}public static void main(String[] args) {//        示例 1int[][] mat = {{1, 1, 3, 2, 4, 3, 2}, {1, 1, 3, 2, 4, 3, 2}, {1, 1, 3, 2, 4, 3, 2}};int i = maxSideLength(mat, 4);System.out.println(i);//        示例 2int[][] mat1 = {{2, 2, 2, 2, 2, 2, 2}, {2, 2, 2, 2, 2, 2, 2}, {2, 2, 2, 2, 2, 2, 2}};int j = maxSideLength(mat1, 1);System.out.println(j);}
}

元素和小于等于阈值的正方形的最大边长(来源:力扣(LeetCode))相关推荐

  1. LeetCode(1292):元素和小于等于阈值的正方形的最大边长 Maximum Side Length of a Square(Java)

    2020.12.24 LeetCode 从零单刷个人笔记整理(持续更新) github:https://github.com/ChopinXBP/LeetCode-Babel 原地动态规划 + 前缀和 ...

  2. 1292. 元素和小于等于阈值的正方形的最大边长-前缀和算法

    1292. 元素和小于等于阈值的正方形的最大边长-前缀和算法 给你一个大小为 m x n 的矩阵 mat 和一个整数阈值 threshold. 请你返回元素总和小于或等于阈值的正方形区域的最大边长:如 ...

  3. leetcode1292. 元素和小于等于阈值的正方形的最大边长(二分法+前缀和)

    给你一个大小为 m x n 的矩阵 mat 和一个整数阈值 threshold. 请你返回元素总和小于或等于阈值的正方形区域的最大边长:如果没有这样的正方形区域,则返回 0 . 示例 2: 输入:ma ...

  4. LeetCode 1292. 元素和小于等于阈值的正方形的最大边长(DP)

    1. 题目 给你一个大小为 m x n 的矩阵 mat 和一个整数阈值 threshold. 请你返回元素总和小于或等于阈值的正方形区域的最大边长: 如果没有这样的正方形区域,则返回 0 . 示例 1 ...

  5. Leetcode-元素和小于等于阈值的正方形的最大边长(python)

    题目 给你一个大小为 m x n 的矩阵 mat 和一个整数阈值 threshold. 请你返回元素总和小于或等于阈值的正方形区域的最大边长:如果没有这样的正方形区域,则返回 0 . 示例 1: 输入 ...

  6. python【力扣LeetCode算法题库】219 -存在重复元素 II

    给定一个整数数组和一个整数 k,判断数组中是否存在两个不同的索引 i 和 j,使得 nums [i] = nums [j],并且 i 和 j 的差的绝对值最大为 k. 示例 1: 输入: nums = ...

  7. python【力扣LeetCode算法题库】217-存在重复元素

    给定一个整数数组,判断是否存在重复元素. 如果任何值在数组中出现至少两次,函数返回 true.如果数组中每个元素都不相同,则返回 false. 示例 1: 输入: [1,2,3,1] 输出: true ...

  8. python【力扣LeetCode算法题库】169-多数元素

    多数元素 给定一个大小为 n 的数组,找到其中的多数元素.多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素. 你可以假设数组是非空的,并且给定的数组总是存在多数元素. 示例 1: 输入: [3 ...

  9. python【力扣LeetCode算法题库】27-移除元素

    移除元素 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度. 不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输 ...

最新文章

  1. Debug Pytorch: RuntimeError: CUDA error: device-side assert triggered
  2. 【数据分析】《唐探3》口碑急转直下?看看影迷们到底都说了些啥
  3. C++模板的那丢丢事儿
  4. Angular应用里使用import直接导入到应用代码里的class,在运行时的表现
  5. docker搜索镜像
  6. treeset 是有序吗_TreeSet如何实现有序?
  7. 至今为止碰到的非常妖怪的计算机问题
  8. android开发动画和壁纸,Android静态壁纸和动态壁纸的使用和理解
  9. JNI引用溢出导致的重启问题分析
  10. 【网络安全】数据加密标准(DES算法)详细介绍( 分组密码、Feistel密码结构、轮函数、子密钥生成算法)
  11. 看不出svp补帧_专业补帧软件SVP4 实现PotPlayer视频补帧教程
  12. 弦图(Chordal Graph)学习小记
  13. 企业集成平台与SOA架构
  14. 中国有两个“造字”故事,一个在远古传说,一个在虚拟现实
  15. 动态规划 计算二项式系数
  16. STM32常见通信方式(TTL、RS232、RS485、I2C,SPI,CAN)总结
  17. FaceBook爬取库:facebook-scraper
  18. 图像算法研究---背景虚化算法
  19. 2022年3月青少年软件编程(Python)等级考试试卷(一级真题)
  20. svg实现水滴相融效果

热门文章

  1. 超定线性方程组Ax=b极小L1范数求解——MATLAB/Python实现
  2. python中类变量和实例变量详解
  3. JS三种等号的区别(=、==、===)
  4. Python类王者荣耀小游戏
  5. 关于在for循环的switch语句使用break和continue问题
  6. grpc client No connection could be made because the target machine actively refused it
  7. MapReduce作业在Hadoop完全分布式集群上运行的问题与思考(持续更新)
  8. Java笔记09——常用类
  9. TNF抑制剂相关的肿瘤风险:阿达木单抗、依那西普和英夫利昔单抗随机对照试验的荟萃分析...
  10. 《SpringCloud Alibaba 微服务架构》专题(二十一)-Seat简介与安装