問題:一個矩陣只含有0 1兩種元素,求只包含1的最大子矩陣大小(大小用包含的1的個數表示)
假設矩陣大小為N x M, 要求時間復雜度為O(N x M)
例如給定如下矩陣:
1 0 1 0 0 1 0 1 1 1 1 1 1 1 1 1 0 0 1 0
Return 4
對這類的矩陣問題,可以逐行解決。
先思考這樣一個問題,如何求一個數組{3 4 5 2 4}圍成的最大面積。
對任意一個位置i,我們需要找到其左右邊第一個小於arr[i]的數的位置p1,p2,則位置i對應的面積是(p2 - p1 - 1)* arr[i]
需要一個輔助棧,壓入彈出規則如下:(注意只壓入下標)
1. 若當前數 arr[i] 大於或等於棧頂數arr[j],壓入當前數的下標i;
2.否則,彈出棧頂數j。此時棧頂數為k,繼續判斷。
只在情況2中計算想要的面積。對彈出的棧頂數j,其右邊第一個比他小的數為arr[i], 其左邊第一個比他小的數為arr[k]. 則對j來說,
其對應的面積為(i - k - 1)* arr[j]
當棧為空, 左邊界為-1 或已經壓入了所有的數組元素,其右邊界就為arr.length
由於每個元素只進棧出棧一次,其復雜度為O(M)
public static int maxRecSize(int[][] map) { if (map == null || map.length == 0 || map[0].length == 0) { return 0; } int maxArea = 0; int[] height = new int[map[0].length]; for (int i = 0; i < map.length; i++) { for (int j = 0; j < map[0].length; j++) { height[j] = map[i][j] == 0 ? 0 : height[j] + 1; } maxArea = Math.max(maxRecFromBottom(height), maxArea); } return maxArea; } public static int maxRecFromBottom(int[] height) { if (height == null || height.length == 0) { return 0; } int maxArea = 0; Stack<Integer> stack = new Stack<Integer>(); for (int i = 0; i < height.length; i++) { while (!stack.isEmpty() && height[i] <= height[stack.peek()]) { int j = stack.pop();//每彈出一個數即開始一次計算 int k = stack.isEmpty() ? -1 : stack.peek();//r若棧空,左邊比他小的數的位置為-1. int curArea = (i - k - 1) * height[j]; maxArea = Math.max(maxArea, curArea); } stack.push(i); }
//壓入所有數之后,右邊界為arr.length while (!stack.isEmpty()) { int j = stack.pop(); int k = stack.isEmpty() ? -1 : stack.peek(); int curArea = (height.length - k - 1) * height[j]; maxArea = Math.max(maxArea, curArea); } return maxArea; }