求最大子矩阵的大小
題目:
給定一個整型矩陣map,其中的值只有0和1兩種,求其中全是1的所有矩形區域中,最大的矩形區域為1的數量。?
例如:?
1 0 1 1?
1 1 1 1?
1 1 1 0?
其中,最大的矩形區域有6個1,所以返回6.
思路:
如果矩陣的大小是O(N*M),本題可以做到時間復雜度為O(N*M)。?
1、矩陣的行數是N,以每一行做切割,統計以當前行作為底的情況下,每個位置往上連續1的數量。使用高度數組height來表示。?
例如:?
map = 1 0 1 1?
? 1 1 1 1?
? 1 1 1 0?
以第一行做切割后,height = {1, 0, 1, 1}.?
以第二行做切割后,height = {2, 1, 2, 2}.?
以第三行做切割后,height = {3, 2, 3, 0}.
2、對于height數組,我們可以將其想象成一個直方圖,要求最大的子矩陣,實際上就是對以每一行為底的直方圖,其最大矩陣面積。如果我們能求出以每一個柱子擴展出去的最大矩形,那么其中最大的矩形就是我們想要的。
如果要求一個柱子a擴展出去的最大矩形,實際上就是求這個柱子左邊第一個比它低的柱子b以及右邊第一個比它低的柱子c,那么b和c之間的柱子數×a柱子的高度,就是答案。問題的關鍵就在于如何快速的找到柱子b和c。方法如下:?
?
使用一個棧,從左到右遍歷數組height,假設遍歷到的位置為i,如果棧為空或者棧頂所對應的元素小于height[i],直接將 i 壓入棧中;否則將棧中大于height[i]的元素全部出棧,然后壓入 i。對于棧中的每一個元素,左邊第一個比它小的數的位置就是棧中上一個元素,右邊第一個比它小(或者等于)的數的位置就是使它出棧的數的位置,如果沒有數使它出棧,說明它右邊沒有比它小的數。
以[1,3,2]為例,首先1入棧,接下來3比1大,直接入棧,并且確定了3左邊第一個比它小的數是1;接下來2比3小,3出棧,同時可以確定3右邊第一個比它小的數是2;接下來2比1大,2入棧,并且確定了2左邊第一個比它小的數是1。此時棧中的元素為[1,2],沒有數使它們出棧,所以1和2右邊都沒有比它小的數。
def getmaxRecsize(L):if L == None or len(L)==0 or len(L[0]) == 0:return 0maxArea = 0height = [0] * len(L[0])for i in range(len(L)):for j in range(len(L)):if L[i][j] == 0:height[j] = 0else:height[j] = height[j] + 1maxArea = max(getMaxArea(height),maxArea)return maxAreadef getMaxArea(height):if height == None or len(height) == 0:return 0stack = []for i in range(len(height)):while len(stack)!=0 and height[stack[-1]] > height[i]:popindex = stack.pop()if len(stack)==0:leftLessindex = -1else:leftLessindex = stack.pop()curArea = (i - leftLessindex -1 1) * height[i]maxArea = max(maxArea,curArea)stack.push(i)while len(stack)!=0:popindex = stack.pop()if len(stack) == 0:leftLessindex = -1else:leftLessindex = stack[-1]curArea = (i - leftLessindex -1) * height[i]maxArea = max(maxArea,curArea)return maxArea?
總結