Leetcode 84. Largest Rectangle in Histogram & 85. Maximal Rectangle

来源:互联网 发布:caffe的test iter 编辑:程序博客网 时间:2024/06/12 20:24

84. Largest Rectangle in Histogram

Total Accepted: 59920 Total Submissions: 246957 Difficulty: Hard

Given n non-negative integers representing the histogram's bar height where the width of each bar is 1, find the area of largest rectangle in the 

histogram.


Above is a histogram where width of each bar is 1, given height = [2,1,5,6,2,3].


The largest rectangle is shown in the shaded area, which has area = 10 unit.

For example,
Given heights = [2,1,5,6,2,3],
return 10.


老实讲,挺怕这种histogram的题的,碰见的逻辑都很强大。什么俩指针,相等就同时向中间移动;或者用stack什么的。就是说这种题给出来很直观,但是算法的都比较不容易想。


想了一会果断不会,然后发现了一篇非常好的文章:http://www.cnblogs.com/lichen782/p/leetcode_Largest_Rectangle_in_Histogram.html

这篇作者讲的非常详细。下面就把碰到的一些细节说出来,吐槽:每次debug碰到小细节问题都要浪费好几个小时蛋疼。。


思路是这样:

比如图中的5,6最大。5的左边全部小于5;6的右边全部小于6。作者的思路是维护一个stack, 使得当前遍历的元素cur一定要大于数组的peek()值。这样数组中的元素是递增的。

每当我们碰到一个小于的元素(这样就保证右边小于了,peek()是last element),一直pop stack直到第一个元素小于了当前的值(这样就保证了左边小于)。于是要做的就是计算出栈这几个元素的结果。

为了清空stack需要额外在数组尾部加入一个0。为了计算方便,stack中存入的是index。


需要注意以下几点:

1. 比如出5, 6。先出6,算一次;然后出5, 5,6算一次。

2. width应该等于 st.isEmpty() ? i : i - st.peek() - 1。这个非常重要。stack不空的时候不等于i-stack last pop()。 

反例就是这个[4,2,0,3,2,5]。先4,碰到2输出4,2入栈。然后碰到0,2输出计算,0入栈。然后碰到3入栈,在碰到2,输出3计算,2入栈。这时候栈里面是【0, 2】。然后碰到5入

栈,最后碰到添加的0,出栈的是5和2!!!! 6-2-1=3 * 2 =6。相当于index 2处的0做了左边界,添加的0做了右边界,然后计算了中间的值。如果用 i-last出栈index,则只能得到

(6-4)*2=4,就错了。

public class Solution {    public int largestRectangleArea(int[] heights) {        Stack<Integer> st = new Stack<Integer>();        int n = heights.length; int res = 0;        for(int i=0; i<=n; i++){            int cur = i==n ? 0: heights[i];            while(!st.isEmpty() && heights[st.peek()]>cur){                    int h = st.pop();                    res = Math.max(res, heights[h]* (st.isEmpty() ? i : i - st.peek()-1));                     // i - h wrong, [4,2,0,3,2,5] if the last matrix is from 3->5 with height of 2, here peek() gives the boundary, if                     // use the index last popped by stack, we will not take care of 3.                    // so the stack guarantees the index we have must be shorter than the index we are calculating now.                    // in this case, index is 5, height is 2, the stack have one element 2, the height of which is 0.                     // the stack tells us when we will find the first element that is shorter than cur!                    // we already make sure the current i index has a smaller value than cur (if larger than current i, pop)            }            st.push(i); // save index for calculation convenience        }        return res;    }}

网上有人用数组实现了stack,运行时间更快:

// The classic stack solution is simpler. However, using collection will be slower. Here is an implementation using int array to simulation a stack. The run time is 5 ms.public class Solution {    public int largestRectangleArea(int[] h) {        int n = h.length;        int max = 0;        int[] stack = new int[n + 1];        int is = -1;        for (int i = 0; i <= n; i++) {            int height = (i == n) ? 0 : h[i];            while (is != -1 && height < h[stack[is]]) {                int hh = h[stack[is--]];                int width = (is == -1) ? i : i - 1 - stack[is];                max = Math.max(max, hh * width);            }            stack[++is] = i;        }        return max;    }}



85. Maximal Rectangle

Total Accepted: 42208 Total Submissions: 178889 Difficulty: Hard

Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing all ones and return its area.


解法一:

将该2D数组化成直方图数组。每一行对应一个直方图,直方图的每列高度是以该点开始,向上连续1的数量。你要问我为啥..我也不知道 然后这道题就相当于84那题,给了m行个直方图,求这m个直方图中的最大值。

public class Solution { // 33ms    public int maximalRectangle(char[][] matrix) {        if(matrix==null||matrix.length==0||matrix[0].length==0) return 0;        int[][] hist = new int[matrix.length][matrix[0].length];        for(int i=0; i<matrix.length; i++){            for(int j=0; j<matrix[0].length; j++){              if(matrix[i][j]=='0') hist[i][j]=0;            else{                hist[i][j]=1; int m=i-1;                while(m>=0 && matrix[m][j]=='1'){                    hist[i][j]++; m--;                }            }              }        }        int res=0;        for(int i=0; i<hist.length; i++){            res = Math.max(res, findMax(hist[i]));        }        return res;    }        public int findMax(int[] hist){        Stack<Integer> st = new Stack<Integer>();        int res=0; int cur;        for(int i=0; i<=hist.length; i++){            if(i==hist.length) cur=0;            else cur=hist[i];            while(!st.isEmpty() && hist[st.peek()]>cur){                int index = st.pop();                int width = st.isEmpty() ? i : i - st.peek() - 1;                res = Math.max(res, hist[index] * width);            }            st.push(i);        }        return res;    }}

解法二:

dp。

http://liangjiabin.com/blog/2015/04/leetcode-maximal-rectangle.html

题目的Tags里给出了动态规划,那么这道题能不能用动态规划解呢?这道题与传统的动规有点不一样,传统的动规只需要从左上角一直遍历到右下角,每往下一步往右一步都由上面和左边的状态来决定当前的状态,最右下角便是最优解。而这道题求最大矩形面积,却需要从上大小,从左到右一次,从右到左一次,保存两个方向的状态。具体来说,从上到下,与上面解法类似,对于每一层i,记录每个点matrix[i][j]正上面字符1的连续高度height[j];从左到右,记录高度为height[j]的矩形左边的起始位置left[j];从右到左,记录高度为height[j]的矩形右边的结束为止;那么matrix[i][j]这个点处的最大矩形面积就是(right[j]-left[j])*height[j]。

public class Solution { // 13ms    public int maximalRectangle(char[][] matrix) {        if(matrix==null||matrix.length==0||matrix[0].length==0) return 0;        int[][] hist = new int[matrix.length][matrix[0].length];        for(int i=0; i<matrix.length; i++){            for(int j=0; j<matrix[0].length; j++){              if(matrix[i][j]=='0') hist[i][j]=0;            else{                hist[i][j]=1; int m=i-1;                while(m>=0 && matrix[m][j]=='1'){                    hist[i][j]++; m--;                }            }              }        }        int res=0;        for(int i=0; i<hist.length; i++){            res = Math.max(res, findMax(hist[i]));        }        return res;    }        public int findMax(int[] hist){        Stack<Integer> st = new Stack<Integer>();        int res=0; int cur;        for(int i=0; i<=hist.length; i++){            if(i==hist.length) cur=0;            else cur=hist[i];            while(!st.isEmpty() && hist[st.peek()]>cur){                int index = st.pop();                int width = st.isEmpty() ? i : i - st.peek() - 1;                res = Math.max(res, hist[index] * width);            }            st.push(i);        }        return res;    }}

0 0
原创粉丝点击