[LeetCode] 84. 柱狀圖中最大的矩形

題目連接 : https://leetcode-cn.com/problems/largest-rectangle-in-histogram/java

題目描述:

給定 n 個非負整數,用來表示柱狀圖中各個柱子的高度。每一個柱子彼此相鄰,且寬度爲 1 。python

求在該柱狀圖中,可以勾勒出來的矩形的最大面積。app

以上是柱狀圖的示例,其中每一個柱子的寬度爲 1,給定的高度爲 [2,1,5,6,2,3]。優化

圖中陰影部分爲所能勾勒出的最大矩形面積,其面積爲 10 個單位。spa

示例:

輸入: [2,1,5,6,2,3]
輸出: 10

思路:

首先,想找到第i位置最大面積是什麼?code

是以i爲中心,向左找第一個小於heights[i]的位置left_i;向右找第一個小於於heights[i]的位置right_i,即最大面積爲heights[i] * (right_i - left_i -1),以下圖所示:blog

因此,咱們的問題就變成如何找right_ileft_i?leetcode

最簡單的思路就是,就是暴力法,直接分別在i左右移動get

class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:
        res = 0
        n = len(heights)
        for i in range(n):
            left_i = i
            right_i = i
            while left_i >= 0 and heights[left_i] >= heights[i]:
                left_i -= 1
            while right_i < n and heights[right_i] >= heights[i]:
                right_i += 1
            res = max(res, (right_i - left_i - 1) * heights[i])
        return res

可是,這是一個時間複雜度爲$O(n^2)$,超時io

接下來想辦法優化.

思路一:

當咱們找i左邊第一個小於heights[i]若是heights[i-1] >= heights[i]其實就是和heights[i-1]左邊第一個小於heights[i-1]同樣.依次類推,右邊同理.

思路二:棧

利用單調棧,我寫過關於它一篇文章

維護一個單調遞增的棧,就能夠找到left_iright_i

代碼:

思路一:

class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:
        if not heights:
            return 0
        n = len(heights)
        left_i = [0] * n
        right_i = [0] * n
        left_i[0] = -1
        right_i[-1] = n
        for i in range(1, n):
            tmp = i - 1
            while tmp >= 0 and heights[tmp] >= heights[i]:
                tmp = left_i[tmp]
            left_i[i] = tmp
        for i in range(n - 2, -1, -1):
            tmp = i + 1
            while tmp < n and heights[tmp] >= heights[i]:
                tmp = right_i[tmp]
            right_i[i] = tmp
        # print(left_i)
        # print(right_i)
        res = 0
        for i in range(n):
            res = max(res, (right_i[i] - left_i[i] - 1) * heights[i])
        return res

java

class Solution {
    public int largestRectangleArea(int[] heights) {
        if (heights == null || heights.length == 0) return 0;
        int n = heights.length;
        int[] left_i = new int[n];
        int[] right_i = new int[n];
        left_i[0] = -1;
        right_i[n - 1] = n;
        int res = 0;
        for (int i = 1; i < n; i++) {
            int tmp = i - 1;
            while (tmp >= 0 && heights[tmp] >= heights[i]) tmp = left_i[tmp];
            left_i[i] = tmp;
        }
        for (int i = n - 2; i >= 0; i--) {
            int tmp = i + 1;
            while (tmp < n && heights[tmp] >= heights[i]) tmp = right_i[tmp];
            right_i[i] = tmp;
        }
        for (int i = 0; i < n; i++) res = Math.max(res, (right_i[i] - left_i[i] - 1) * heights[i]);
        return res;  
    }
}

思路二:

class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:
        stack = []
        heights = [0] + heights + [0]
        res = 0
        for i in range(len(heights)):
            #print(stack)
            while stack and heights[stack[-1]] > heights[i]:
                tmp = stack.pop()
                res = max(res, (i - stack[-1] - 1) * heights[tmp])
            stack.append(i)
        return res

java

class Solution {
    public int largestRectangleArea(int[] heights) {
        int res = 0;
        Deque<Integer> stack = new ArrayDeque<>();
        int[] new_heights = new int[heights.length + 2];
        for (int i = 1; i < heights.length + 1; i++) new_heights[i] = heights[i - 1];
        //System.out.println(Arrays.toString(new_heights));
        for (int i = 0; i < new_heights.length; i++) {
            //System.out.println(stack.toString());
            while (!stack.isEmpty() && new_heights[stack.peek()] > new_heights[i]) {
                int cur = stack.pop();
                res = Math.max(res, (i - stack.peek() - 1) * new_heights[cur]);
            }
            stack.push(i);
        }
        return res;  
    }
}
相關文章
相關標籤/搜索