leetcode题解-363. Max Sum of Rectangle No Larger Than K
来源:互联网 发布:mac mini 固态 编辑:程序博客网 时间:2024/06/07 23:05
题目:
Given a non-empty 2D matrix matrix and an integer k, find the max sum of a rectangle in the matrix such that its sum is no larger than k.Example:Given matrix = [ [1, 0, 1], [0, -2, 3]]k = 2The answer is 2. Because the sum of rectangle [[0, 1], [-2, 3]] is 2 and 2 is the max number no larger than k (k = 2).Note:The rectangle inside the matrix must have an area > 0.What if the number of rows is much larger than the number of columns?
这是binary-search里面的hard难度的题目,确实很难,只想到了最暴力的解法,那就是对矩阵中的每个元素遍历其所有可能存在的矩阵,然后求出矩阵的和,然后取所有小于k的最大的和返回。时间复杂度是O(n^4)。思路就是先遍历矩阵将每个元素到左上角的矩阵的和保存在矩阵中,然后遍历每个元素,对每个元素再遍历所有可能存在的矩阵,对每个矩阵都求其和即可。代码入下:
public int maxSumSubmatrix(int[][] matrix, int k) { if (matrix == null || matrix.length == 0 || matrix[0].length == 0) return 0; int rows = matrix.length, cols = matrix[0].length; int[][] areas = new int[rows][cols]; //计算每个元素到左上角元素的和,方便后面使用 for (int r = 0; r < rows; r++) { for (int c = 0; c < cols; c++) { int area = matrix[r][c]; if (r-1 >= 0) area += areas[r-1][c]; if (c-1 >= 0) area += areas[r][c-1]; if (r-1 >= 0 && c-1 >= 0) area -= areas[r-1][c-1]; areas[r][c] = area; } } int max = Integer.MIN_VALUE; for (int r1 = 0; r1 < rows; r1++) { for (int c1 = 0; c1 < cols; c1++) { //遍历数组中的每一个元素,然后下面两个循环是得到其所有可能的矩阵 for (int r2 = r1; r2 < rows; r2++) { for (int c2 = c1; c2 < cols; c2++) { //计算当前矩阵的和 int area = areas[r2][c2]; if (r1-1 >= 0) area -= areas[r1-1][c2]; if (c1-1 >= 0) area -= areas[r2][c1-1]; if (r1-1 >= 0 && c1 -1 >= 0) area += areas[r1-1][c1-1]; if (area <= k) max = Math.max(max, area); } } } } return max; }
自然,这种方法的效率也很低,击败了30%多的用户。然后看别人的方法发现一般采用按列求和的方式,并使用两个数组来保存矩阵的和。先看代码再结合代码进行解释(这里默认行数小于列数)。
public int maxSumSubmatrix2(int[][] matrix, int k) { int m = matrix.length, n = matrix[0].length, ans = Integer.MIN_VALUE; long[] sum = new long[m+1]; // stores sum of rect[0..p][i..j] //注意这里的三个循环,第一层是矩阵的左边,也就是起始位置,第二层是矩阵的右边,也就是结束为止,对每个起始位置,都遍历所有可能的结束位置,得到不同的矩阵。然后第三层是遍历每一行,也就是前面两层确定了矩阵的边界,但是还可能包含不同行的情况。 for (int i = 0; i < n; ++i) { long[] sumInRow = new long[m]; for (int j = i; j < n; ++j) { // for each rect[*][i..j] for (int p = 0; p < m; ++p) { //对每个小矩阵求和。sunInRow是对每一行的所有元素求和,sum是对行之间求和,也就是矩阵的和。 sumInRow[p] += matrix[p][j]; sum[p+1] = sum[p] + sumInRow[p]; } //对sum数组进行归并搜索,找到小于k的值。 ans = Math.max(ans, mergeSort(sum, 0, m+1, k)); if (ans == k) return k; } } return ans; } static int mergeSort(long[] sum, int start, int end, int k) { if (end == start + 1) return Integer.MIN_VALUE; // need at least 2 to proceed int mid = start + (end - start) / 2, cnt = 0; int ans = mergeSort(sum, start, mid, k); if (ans == k) return k; ans = Math.max(ans, mergeSort(sum, mid, end, k)); if (ans == k) return k; long[] cache = new long[end - start]; for (int i = start, j = mid, p = mid; i < mid; ++i) { while (j < end && sum[j] - sum[i] <= k) ++j; if (j - 1 >= mid) { ans = Math.max(ans, (int) (sum[j - 1] - sum[i])); if (ans == k) return k; } while (p < end && sum[p] < sum[i]) cache[cnt++] = sum[p++]; cache[cnt++] = sum[i]; } System.arraycopy(cache, 0, sum, start, cnt); return ans; }
上面这种方法通过三层搜索加一层归并将时间复杂度降低到了O(N^2Mlog(M))。可以击败90%以上的用户。原因在于第一种方法遍历一个矩阵需要四层迭代,而这种方法简化为三层。可以画图结合这理解一下函数运行的过程。
此外,还有一种居中的方法,思路与这种方法类似,不过使用Tree结构来保存内层循环的值并进行二叉搜索得到小于k的最大值,可以击败60%的用户。代码如下所示,这种方法考虑了行数大于列数的情况。
public int maxSumSubmatrix1(int[][] matrix, int target) { int row = matrix.length; if(row==0)return 0; int col = matrix[0].length; int m = Math.min(row,col); int n = Math.max(row,col); //indicating sum up in every row or every column boolean colIsBig = col>row; int res = Integer.MIN_VALUE; for(int i = 0;i<m;i++){ int[] array = new int[n]; // sum from row j to row i for(int j = i;j>=0;j--){ int val = 0; TreeSet<Integer> set = new TreeSet<>(); set.add(0); //traverse every column/row and sum up for(int k = 0;k<n;k++){ array[k]=array[k]+(colIsBig?matrix[j][k]:matrix[k][j]); val = val + array[k]; //use TreeMap to binary search previous sum to get possible result Integer subres = set.ceiling(val-target); if(null!=subres){ res=Math.max(res,val-subres); } set.add(val); } } } return res; }
阅读全文
0 0
- [leetcode] 363. Max Sum of Rectangle No Larger Than K
- leetcode.363. Max Sum of Rectangle No Larger Than K
- [LeetCode]--363. Max Sum of Rectangle No Larger Than K
- leetcode-363. Max Sum of Rectangle No Larger Than K
- Leetcode 363. Max Sum of Rectangle No Larger Than K
- 【Leetcode】363. Max Sum of Rectangle No Larger Than K
- [leetcode]363. Max Sum of Rectangle No Larger Than K
- leetcode 363. Max Sum of Rectangle No Larger Than K
- leetcode题解-363. Max Sum of Rectangle No Larger Than K
- Leetcode Max Sum of Rectangle No Larger Than K
- [LeetCode]Max Sum of Rectangle No Larger Than K
- leetcode(363):Max Sum of Rectangle No Larger Than K
- [LeetCode] Max Sum of Rectangle No Larger Than K
- 【Leetcode】Max Sum of Rectangle No Larger Than K
- 363. Max Sum of Rectangle No Larger Than K
- 363. Max Sum of Rectangle No Larger Than K[hard]
- 363. Max Sum of Rectangle No Larger Than K
- 363. Max Sum of Rectangle No Larger Than K
- 自用创建Samba服务器
- beyond Compare 破解办法(不需补丁)
- 10.15 c语言基础
- tensorflow安装问题:No module named '_pywrap_tensorflow_internal'
- js中const,var,let区别
- leetcode题解-363. Max Sum of Rectangle No Larger Than K
- 代理模式-JDK动态代理
- url-pattern的匹配规则
- Eclipse+Spring学习(一)环境搭建
- centos7 配置静态ip
- 对象的初始化过程
- 深入理解java线程池
- SEO从业五年,软文编写经验总结
- InputStream和OutputStream输入和输出流