求最大子矩陣的大小(單調棧)

單調棧

1. 單調棧的結構

背景:給定一個數組,求數組中每一個元素的左邊距離其最近的比它小的值,和右邊距離其最近的比它小的值。

數組:arr:{3,5,4,2,6}

arr[i] left right
3 null 2
5 3 4
4 3 2
2 null null
6 2 null

思路:設計一個棧,依次存入的元素大於等於棧頂元素,保持棧中元素從下往上逐漸增大。

  • 如果要存入的元素num大於棧頂,則直接入棧。
  • 如果要存入的元素num等於棧頂,則一起存入棧頂(棧頂中的每一個元素可以用鏈表實現)。
  • 如果要存入的元素num小於棧頂,則彈出棧頂元素peek,則numpeek的右邊距離其最近且小於它的元素。當彈出peek後,此時的棧頂元素peekCurpeek的左邊距離其最近且小於它的元素。
  • 當遍歷完數組,棧不爲空的話,依次彈出棧頂元素peek,此時該peek的右邊距離其最近且小於它的元素爲null,左邊距離其最近且小於它的元素爲下一個棧頂元素。

2. 最大拼接的面積

題目:有如下矩形圖,求該矩形圖中能拼接成矩形的最大面積。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-kSLs7rIM-1584967447649)(D:\文檔\學習筆記\刷題2\images\單調棧\1584116775791.png)]

思路:用單調棧判斷每個矩形左右兩邊,距離其最近,且比其矮的矩形。

題解

  • 黃色矩形高爲5,由於右邊棕色矩形比黃色矩形高,所以黃色矩形可以和棕色矩形拼接成高爲5,寬爲2的矩形。
  • 由於棕色矩形左右兩邊的矩形都比它低,所以它能拼接成的矩形是他自己。高爲6,寬爲1。
  • 橙色矩形最低,能拼接所有矩形,最終形成一個高爲3,寬爲5的矩形。
  • 藍色矩形也不能和其他矩形拼接,高爲7,寬爲1。
  • 綠色矩形能和藍色矩形拼接,形成高爲4,寬爲2的矩形。

3. 求最大子矩陣的大小

題目:給定一個整型矩陣map, 其中的值只有0 和 1 兩種, 求其中全是1 的所有矩形區域中, 最大的矩形區域爲1的數量。


1 0 1 1
1 1 1 1
1 1 1 0

其中,最大的矩形區域有6個1,所以返回6 。

思路:把矩陣的每一行看成矩形圖。

  • 如第一行[1,0,1,1],把它看成矩形圖,由四個矩形組成,高分別爲1,0,1,1,寬都爲1。求矩形最大拼接面積。
  • 第二行1,1,1,1和第一行[1,0,1,1]組合起來,組成一個矩形圖,四個矩形高分別2,1,2,2,寬都爲1。求矩形最大拼接面積。
  • 最後一行把整個矩陣看成一個矩形圖,注意,四個矩形高分別爲3,2,3,0。求矩形最大拼接面積。
  • 得到的矩形最大拼接面積的最大值即爲結果。

代碼

import java.util.Stack;

class Solution_MaxArea{

    public static int maxAreaMatrix(int[][] arr){
        //判斷矩陣是否爲空
        if(arr == null || (arr.length == 1 && arr[0].length == 0) || arr.length == 0){
            return 0;                                                                                                    
        }
        int result = Integer.MIN_VALUE;
        int[] rectangle = new int[arr[0].length];
        for(int i = 0; i < arr.length; i++){
            for(int j = 0; j < arr[i].length; j++){
                rectangle[j] = arr[i][j] == 0 ? 0 : rectangle[j] + arr[i][j];
            }
            result = Math.max(maxAreaRectangle(rectangle), result);
        }
        return result;

    }

    public static int maxAreaRectangle(int[] arr){
        if(arr == null || arr.length == 0){
            return 0;
        }
        int len = arr.length;
        Stack<Integer> stack = new Stack<>();
        int res = Integer.MIN_VALUE;
        //哪個元素先彈出,先計算以其代表的矩形的高爲最大矩形的高,在遍歷到的所有矩形中能合併成的最大矩形 的面積
        for(int i = 0; i < len; i++){
            //注意,是大於等於號。
            while(!stack.isEmpty() && arr[stack.peek()] >= arr[i]){
                int height = arr[stack.pop()];
                int left = stack.isEmpty() ? -1 : stack.peek();
                int right = i;
                int area = height * (right - left - 1);
                res = Math.max(area, res);
            }
            stack.push(i);
        }
        while(!stack.isEmpty()){
            int height = arr[stack.pop()];
            int right = len;
            int left = stack.isEmpty() ? -1 : stack.peek();
            int area = height * (right - left - 1);
            res = Math.max(area, res);
        }
        return res;
    }

    public static void main(String[] args) {
        int[][] arr = {{1,0,1,1},{1,1,1,1},{1,1,1,0}};
        System.out.println(maxAreaMatrix(arr));
    }
}

注意: maxAreaRectangle求最大矩形面積的過程比較特別,對於沒有遍歷到的矩形,暫時不將其考慮進最大拼接矩形的範圍中。比如說矩形2,2,4,6,2,當遍歷到i=1時,棧頂元素爲1,由於棧頂元素所代表的值爲2,與arr[2]相等,所以需要彈出。當前只遍歷過一個矩形,所以能形成的最大矩形也就是棧頂元素所代表的那個矩形。
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章