Leetcode编程练习二:求直方图中矩形最大面积

来源:互联网 发布:大数据营销 编辑:程序博客网 时间:2024/04/28 19:52

Leetcode编程练习二:求直方图中矩形最大面积
题目原文描述:(id=84)
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.Below 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.
这里写图片描述这里写图片描述
题目的输入为一个整数数列,输出用这个整数数列表示的直方图中矩形最大面积。由于矩形的所有区域必须被包含在直方图中,而且直方图每一项宽度都是一,所以这样的矩形所包括的直方图项中必然涵盖一个和矩形高度相同值的项,且这个项的值是矩形范围内所有元素的最小值。例子中这个元素就是5.由于这个项和我们要找的矩形是唯一对应的,我们可以通过对每一项进行判断,找到这一项左边和右边连续的比它小的元素的个数,它们的和就是矩形的宽了。现在我们的任务是对每一项求这个宽度,最简单的方法是从这个元素开始分别向左和向右扫描找到连续的和它相连不比它小的值的个数,这种方法时间复杂度是O(n^2),这个方法在leetcode平台的测试数据上直接超时了。

class Solution {public:    int largestRectangleArea(vector<int>& heights) {    int n=heights.size();    vector<int> left(n);    //左边区间长度    if (n==0) return 0;    left[0]=0;    for (int i=1;i<n;i++){        left[i]=0;        int p=i-1;        while (p>=0&&heights[p]>=heights[i])            left[i]++;    }    vector<int> right(n);   //右边区间长度    right[n-1]=n-1;    for (int i=n-2;i>=0;i--){        right[i]=0;        int p=i+1;        while (p<n&&heights[p]>=heights[i])            right[i]++;    }     int ans=0;    for (int i=0;i<n;i++){        ans=max(ans,heights[i]*(right[i]+left[i]+1));    }     return ans;    }};

但是根据以往记忆化搜索的经验,我们是不需要对整一段区间做扫描的,因为我们知道一个项前面的元素连着的不比它小的元素有多少个,如果我们当前处理的元素比前面的元素大,这个区间长度就是0,如果不比它大,就可以在前一次循环求得的区间为基础再向前找,而上述的过程是可以迭代的,直到找到一个比原来元素小的“相邻项”,对于右边的区间可采用类似的手段完成计算。下面代码在leetcode上用时18ms

class Solution {public:    int largestRectangleArea(vector<int>& heights) {    int n=heights.size();    vector<int> left(n);    //连续最左边不比height[i]大的数下标     if (n==0) return 0;    left[0]=0;    for (int i=1;i<n;i++){        if (heights[i]>heights[i-1]){            left[i]=i;        }         else{            left[i]=left[i-1];            int p=left[i-1]-1;            while (p>=0&&heights[i]<=heights[p]){                left[i]=left[p];                p=left[p]-1;            }        }    }    vector<int> right(n);    right[n-1]=n-1;    for (int i=n-2;i>=0;i--){        if (heights[i]>heights[i+1]){            right[i]=i;        }        else{            right[i]=right[i+1];            int p=right[i+1]+1;            while (p<n&&heights[i]<=heights[p]){                right[i]=right[p];                p=right[p]+1;            }        }    }     int ans=0;    for (int i=0;i<n;i++){        ans=max(ans,heights[i]*(right[i]-left[i]+1));    }     return ans;    }};
这个方法的效果受数据影响,如果一个元素前面有很长的一段递增串,就起不到减少扫描元素的效果。
0 0
原创粉丝点击