摘要:思路一暴力循環(huán)如果我們將矩陣中的每個子矩陣都枚舉出來,并計算其元素和,從而得出小于的最大值即可。
題目要求
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: Input: matrix = [[1,0,1],[0,-2,3]], k = 2 Output: 2 Explanation: Because the sum of rectangle [[0, 1], [-2, 3]] is 2, and 2 is the max number no larger than k (k = 2). Note: 1. The rectangle inside the matrix must have an area > 0. 2. What if the number of rows is much larger than the number of columns?
現(xiàn)有一個由整數(shù)構(gòu)成的矩陣,問從中找到一個子矩陣,要求該子矩陣中各個元素的和為不超過k的最大值,問子矩陣中元素的和為多少?
注:后面的文章中將使用[左上角頂點(diǎn)坐標(biāo),右下角頂點(diǎn)坐標(biāo)]來表示一個矩陣,如[(1,2),(3,4)]表示左上角頂?shù)糇鴺?biāo)為(1,2),右下角頂點(diǎn)坐標(biāo)為(3,4)的矩陣。用S[(1,2),(3,4)]表示該矩陣的面積。頂點(diǎn)的坐標(biāo)系以數(shù)組的起始點(diǎn)作為起點(diǎn),向下為x軸正方向,向右為y軸正方向。
如果我們將矩陣中的每個子矩陣都枚舉出來,并計算其元素和,從而得出小于K的最大值即可。
這里通過一個額外的二維數(shù)組S緩存了[(0,0), (i,j)]的矩形的面積,可以通過O(n^2)的時間復(fù)雜度完成計算,即S[i][j] = matrix[i][j] + S[i-1][j] + S[i][j-1] - S[i-1][j-1], 則矩形[(r1,c1),(r2,c2)]的面積為S[r2][c2] -S[r1-1][c2] - S[r2][c1-1] + S[r1-1][c1-1]。這種算法的時間復(fù)雜度為O(N^4),因?yàn)樾枰ㄎ痪匦蔚乃膫€頂點(diǎn),一共需要四圈循環(huán),代碼如下:
public int maxSumSubmatrix(int[][] matrix, int k) { int row = matrix.length; if(row == 0) return 0; int col = matrix[0].length; if(col == 0) return 0; //rectangle[i][j]記錄頂點(diǎn)為[0,0],[i,j]的矩形的面積 int[][] rectangle = new int[row][col]; for(int i = 0 ; i思路二:利用二分法思路進(jìn)行優(yōu)化0) { area += rectangle[i-1][j]; } if(j>0) { area += rectangle[i][j-1]; } //減去重復(fù)計算的面積 if(i>0 && j>0) { area -= rectangle[i-1][j-1]; } rectangle[i][j] = area; } } int result = Integer.MIN_VALUE; for(int startRow = 0 ; startRow
0) { area -= rectangle[startRow-1][endCol]; } if(startCol > 0) { area -= rectangle[endRow][startCol-1]; } if(startRow > 0 && startCol > 0) { area += rectangle[startRow-1][startCol-1]; } if (area <= k) result = Math.max(result, area); } } } } return result; }
對算法從時間上優(yōu)化的核心思路就是盡可能的減少比較或是計算的次數(shù)。上面一個思路的我們可以理解為以row1和row2分別作為子矩陣的上邊界和下邊界,以col2作為右邊界,要求找到一個左邊界col1,使得其劃分出來的子矩陣中元素的和為小于等于k的最大值,即
max(S[(row1,0),(row2, col2)] - S[(row1,0),(row2, col1)]) && col1 < col2 && S[(row1,0),(row2, col2)] - S[(row1,0),(row2, col1)]換句話說,假如將col2左側(cè)的所有以最左側(cè)邊為起點(diǎn)的子矩陣按照元素和從小到大排隊,即將子矩陣(row1, 0), (row2, colx) 其中colx < col2按照元素和從小到大排序,此時只需要在該結(jié)果中找到一個矩陣,其值為大于等于S[(row1,0),(row2, col2)] - k的最小值。此時得出的矩陣元素和差最大。這里采用TreeSet來實(shí)現(xiàn)O(logN)的元素查找時間復(fù)雜度。
代碼如下:
public int maxSumSubmatrix2(int[][] matrix, int k) { int row = matrix.length; if(row == 0) return 0; int col = matrix[0].length; if(col == 0) return 0; //rectangle[i][j]記錄頂點(diǎn)為[0,0],[i,j]的矩形的面積 int[][] rectangle = new int[row][col]; for(int i = 0 ; i思路三:分治法0) { area += rectangle[i-1][j]; } if(j>0) { area += rectangle[i][j-1]; } //減去重復(fù)計算的面積 if(i>0 && j>0) { area -= rectangle[i-1][j-1]; } rectangle[i][j] = area; } } int result = Integer.MIN_VALUE; for(int startRow = 0 ; startRow < row ; startRow++) { for(int endRow = startRow ; endRow < row ; endRow++) { //記錄從startRow到endRow之間所有以最左側(cè)邊為起點(diǎn)的矩形的面積 TreeSet
treeSet = new TreeSet (); treeSet.add(0); for(int endCol = 0 ; endCol < col ; endCol++) { int area = rectangle[endRow][endCol]; if(startRow > 0) { area -= rectangle[startRow-1][endCol]; } //可以減去的左側(cè)矩形的最小面積,即大于S[(row1,0),(row2, col2)] - k的最小值 Integer remain = treeSet.ceiling(area - k); if(remain != null) { result = Math.max(result, area - remain); } treeSet.add(area); } } } return result; } 從上面兩種思路,我們可以將題目演化成另一種思路,即對于任意以row1和row2作為上下邊界的子矩陣,將其中每一列的元素的和記為sum[colx](0<=colx
,則生成一個長度為col的整數(shù)數(shù)組sum。需要從該整數(shù)數(shù)組中找到一個連續(xù)的子數(shù)組,使得該子數(shù)組的和最大且不超過k。 連續(xù)子數(shù)組的和是一道非常經(jīng)典的動態(tài)規(guī)劃的問題,它可以在nlogn的時間復(fù)雜度內(nèi)解決。這里采用歸并排序的思路來進(jìn)行解決。本質(zhì)上將數(shù)組以中間位置分割為左子數(shù)組和右子數(shù)組,分別求左子數(shù)組內(nèi)和右子數(shù)組內(nèi)最大的連續(xù)子數(shù)組和,并且在遞歸的過程中將左右子數(shù)組中的元素分別從小到大排序。接著判斷是否有橫跨中間節(jié)點(diǎn)的子數(shù)組滿足題目要求,因?yàn)樽笥易訑?shù)組分別有序,因此一旦遇到一個右邊界,其和左邊界構(gòu)成的矩陣的元素的和超過k,就可以停止右指針的移動。因此每次中間結(jié)果的遍歷只需要O(N)的時間復(fù)雜度。
代碼如下:
public int maxSumSubmatrix3(int[][] matrix, int k) { int row = matrix.length; if(row == 0) return 0; int col = matrix[0].length; if(col == 0) return 0; int result = Integer.MIN_VALUE; int[] sums = new int[row+1];//sums[i]記錄startCol到endCol列之間,0行到i行構(gòu)成的矩陣的面積 for(int startCol = 0 ; startColmid) { ans = Math.max(sums[j-1] - sums[i], ans); if (ans == k) return k; } while(m
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/74850.html
摘要:題目鏈接參考里的解釋先是如何在矩陣?yán)镎业膯栴},參考視頻然后就是一個里面找不大于的最大值問題了要找到最大的用就是,就是來做了。行和列哪個打就用另一個掃。另外找最大不超過的還可以用,參考 363. Max Sum of Rectangle No Larger Than K 題目鏈接:https://leetcode.com/problems... 參考discussion里的解釋:http...
Problem Given an array nums and a target value k, find the maximum length of a subarray that sums to k. If there isnt one, return 0 instead. Note The sum of the entire nums array is guaranteed to fit ...
摘要: Problem In a given array nums of positive integers, find three non-overlapping subarrays with maximum sum. Each subarray will be of size k, and we want to maximize the sum of all 3*k entries. R...
Problem For a web developer, it is very important to know how to design a web pages size. So, given a specific rectangular web page’s area, your job by now is to design a rectangular web page, whose l...
摘要:題目要求代表對數(shù)組在位置上進(jìn)行順時針的旋轉(zhuǎn)后生成的數(shù)組。暴力循環(huán)按照題目的要求,執(zhí)行兩次循環(huán)即可以獲得的所有值,只需要從中比較最大值即可。 題目要求 Given an array of integers A and let n to be its length. Assume Bk to be an array obtained by rotating the array A k p...
閱讀 3576·2023-04-25 14:20
閱讀 1203·2021-09-10 10:51
閱讀 1157·2019-08-30 15:53
閱讀 466·2019-08-30 15:43
閱讀 2320·2019-08-30 14:13
閱讀 2798·2019-08-30 12:45
閱讀 1209·2019-08-29 16:18
閱讀 1169·2019-08-29 16:12