zoukankan      html  css  js  c++  java
  • LeetCode(84): 柱状图中最大的矩形

    Hard!

    题目描述:

    给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。

    求在该柱状图中,能够勾勒出来的矩形的最大面积。

    以上是柱状图的示例,其中每个柱子的宽度为 1,给定的高度为 [2,1,5,6,2,3]

    图中阴影部分为所能勾勒出的最大矩形面积,其面积为 10 个单位。

    示例:

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

    解题思路:

    这道题让求直方图中最大的矩形,http://fisherlei.blogspot.com/2012/12/leetcode-largest-rectangle-in-histogram.html这里有一种很好的优化方法,就是遍历数组,每找到一个局部峰值,然后向前遍历所有的值,算出共同的矩形面积,每次对比保留最大值。

    C++解法一:

     1 // Pruning optimize
     2 class Solution {
     3 public:
     4     int largestRectangleArea(vector<int> &height) {
     5         int res = 0;
     6         for (int i = 0; i < height.size(); ++i) {
     7             if (i + 1 < height.size() && height[i] <= height[i + 1]) {
     8                 continue;
     9             }
    10             int minH = height[i];
    11             for (int j = i; j >= 0; --j) {
    12                 minH = min(minH, height[j]);
    13                 int area = minH * (i - j + 1);
    14                 res = max(res, area);
    15             }
    16         }
    17         return res;
    18     }
    19 };

    还有一种比较流行的解法,是利用栈来解,详见http://www.cnblogs.com/lichen782/p/leetcode_Largest_Rectangle_in_Histogram.html,但是经过仔细研究,其核心思想跟上面那种剪枝的方法有异曲同工之妙,这里维护一个栈,用来保存递增序列,相当于上面那种方法的找局部峰值。

    我们可以看到,直方图形面积要最大的话,需要尽可能的使用连续的矩形多,并且最低一块的高度要高。有点要木桶原理一样,总是最低的那块板子决定桶的装水量。那么既然需要用单调栈来做,首先要考虑到底用递增栈,还是用递减栈来做。

    增栈是维护递增的顺序,当遇到小于栈顶元素的数就开始处理,而递减栈正好相反,维护递减的顺序,当遇到大于栈顶元素的数开始处理。那么根据这道题的特点,我们需要按从高板子到低板子的顺序处理,先处理最高的板子,宽度为1,然后再处理旁边矮一些的板子,此时长度为2,因为之前的高板子可组成矮板子的矩形 ,因此我们需要一个递增栈,当遇到大的数字直接进栈,而当遇到小于栈顶元素的数字时,就要取出栈顶元素进行处理了,那取出的顺序就是从高板子到矮板子了,于是乎遇到的较小的数字只是一个触发,表示现在需要开始计算矩形面积了,为了使得最后一块板子也被处理,这里用了个小trick,在高度数组最后面加上一个0,这样原先的最后一个板子也可以被处理了。由于栈顶元素是矩形的高度,那么关键就是求出来宽度,那么跟之前那道Trapping Rain Water一样,单调栈中不能放高度,而是需要放坐标。由于我们先取出栈中最高的板子,那么就可以先算出长度为1的矩形面积了,然后再取下一个板子,此时根据矮板子的高度算长度为2的矩形面积,以此类推,知道数字大于栈顶元素为止,再次进栈,很是巧妙!关于单调栈问题可以参见http://www.cnblogs.com/grandyang/p/8887985.html

    C++解法二:

     1 class Solution {
     2 public:
     3     int largestRectangleArea(vector<int> &height) {
     4         int res = 0;
     5         stack<int> st;
     6         height.push_back(0);
     7         for (int i = 0; i < height.size(); ++i) {
     8             if (st.empty() || height[st.top()] < height[i]) {
     9                 st.push(i);
    10             } else {
    11                 int cur = st.top(); st.pop();
    12                 res = max(res, height[cur] * (st.empty() ? i : (i - st.top() - 1)));
    13                 --i;
    14             }     
    15         }
    16         return res;
    17     }
    18 };

    我们可以将上面的方法稍作修改,使其更加简洁一些:

    C++解法二:

     1 class Solution {
     2 public:
     3     int largestRectangleArea(vector<int>& heights) {
     4         int res = 0;
     5         stack<int> st;
     6         heights.push_back(0);
     7         for (int i = 0; i < heights.size(); ++i) {
     8             while (!st.empty() && heights[st.top()] >= heights[i]) {
     9                 int cur = st.top(); st.pop();
    10                 res = max(res, heights[cur] * (st.empty() ? i : (i - st.top() - 1)));
    11             }
    12             st.push(i);
    13         }
    14         return res;
    15     }
    16 };
  • 相关阅读:
    如何在SpringMVC项目中部署WebService服务并打包生成客户端
    Spring MVC前后端数据交互总结
    JAVA总结---序列化的三种方式
    jackson中的@JsonBackReference和@JsonManagedReference,以及@JsonIgnore
    Jackson-deserialization fails on circular dependencies(JackSon无限递归问题)
    @JsonIgnore @JsonIdentityInfo 处理Hibernate 循环引用的问题
    hibernate中因双向依赖而造成的json怪相--springmvc项目
    jackson java转json hibernate懒加载造成的无限递归问题
    C/C++使用心得:enum与int的相互转换
    浅析长子继承制对英国社会的影响
  • 原文地址:https://www.cnblogs.com/ariel-dreamland/p/9159207.html
Copyright © 2011-2022 走看看