leecode 解题总结:84. Largest Rectangle in Histogram
2017-02-13 13:31
204 查看
#include <iostream> #include <stdio.h> #include <vector> #include <set> #include <stack> using namespace std; /* 问题: 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. 分析:这道题目需要从矩阵图中找到面积最大的矩阵,矩阵条的高度等于数组中给定值的高度。 暴力破解:遍历每个bar,然后遍历高度1~h,对每个高度从当前一直到最后一个bar。 或者简单一点,罗列出每个起始bar和终止bar,然后设定高度为从起始bar到终止bar中高度的最小值 时间复杂度为O(n^2)。因为从一组数里选择最小的数时间复杂度为O(n)或者O(logN)用小丁对 但是不一定[low,high]的面积=(high-low+1)*minHeight,可能会是其他。 是否可以选定一个中心,然后向两边扩散。 如果中心的左边>右边,那么应该优先选择哪一边 有点累似盛水的题目,盛水从左和从右分别维持两个指针,和leftMax,rightMax,如果leftMax < rightMax, 以左边为基准。 未能解答出。 网上解法: 从左导游遍历所有bar,每个bar仅雅茹到栈一次。一个bar会被弹出,当前遇到一个较小高度的bar。当一个bar被弹出时, 我们计算弹出的bar的面积并作为最小的bar。如何获取弹出bar左边和右边的下标? 当前的下标告诉了我们右边的下标,而在栈中存储的前一个bar就是左边的下标。 步骤: 1】创建空栈,设直方图为hists[i],i从0到n-1。 2】如果栈为空,或者当前hists[i]>=栈顶高度,就压入i 否则,如果hists[i] < 栈顶对应元素高度,就移出栈顶,直到栈顶元素高度<=hist[i], 在此过程中不断计算面积,该面积是所有大于hists[i]的连续bar组成的矩阵面积 输入: 6(数组元素个数) 2 1 5 6 2 3 7 6 2 5 4 5 1 6 输出: 10 12 关键: 1 核心思想是:维护一个单调非递减的区间[low,high],而栈stack中存放了非递减区间的元素下标,一旦找到当前元素(对应下标为i)<栈顶元素,则开始计算面积 面积 = 当前高度 * (终点 - 起点 + 1),满足:终点对应元素高度>=当前高度,起点对应元素高度>=当前高度 由于是单调非递减区间 弹出一次栈顶,新的栈顶对应元素高度<=当前高度,那么新的栈顶记录的位置+1 对应元素高度 >= 当前高度【关键】 所以起点 = 新的栈顶记录的位置 + 1 终点 = i - 1 面积 = 当前高度 * (i - 1 - (新的栈顶记录的位置+1) + 1) = 当前高度 * ( i - 1 - 新的栈顶记录的位置) //首先明确hists中存放了单调非递减区间对应高度的下标,所以heights[删除栈顶后的新top] <= heights[top] while(i < n) { //当前元素高度>=栈顶元素高度,压入栈中。为的是寻找递增区间 if(hists.empty() || heights.at(i) >= heights[hists.top()] ) { hists.push(i++); } //当前元素高度< 栈顶元素高度,开始计算最大面积 else { top = hists.top();//top是当前递增区间终止bar的下标,用于计算高度 hists.pop();//这里之所以要弹出,是因为 //宽度=i-1(递增高度最大值对应下标) - 弹出当前元素后的栈顶高度 if(hists.empty()) { width = i;//表明0~i-1都是递增区间,长度为i } else { //这样理解i是第一个小于递增区间的下标。 i-1是递增区间的终止下标,那么hists.top()+1对应的是大于等于当前元素高度的起始结点下标 //宽度=终点-起点+1=i-1 - (hists.top() + 1) + 1 = i - 1 - hists.top() width = i - 1 - hists.top(); } area = heights.at(top) * width;//注意对应高度是top下标对应高度 if(area > maxArea) { maxArea = area; } } } */ class Solution { public: int largestRectangleArea(vector<int>& heights) { if(heights.empty()) { return 0; } stack<int> hists; int i = 0 ; int n = heights.size(); int area; int maxArea = INT_MIN; int top; int width; //首先明确hists中存放了单调非递减区间对应高度的下标,所以heights[删除栈顶后的新top] <= heights[top] while(i < n) { //当前元素高度>=栈顶元素高度,压入栈中。为的是寻找递增区间 if(hists.empty() || heights.at(i) >= heights[hists.top()] ) { hists.push(i++); } //当前元素高度< 栈顶元素高度,开始计算最大面积 else { top = hists.top();//top是当前递增区间终止bar的下标,用于计算高度 hists.pop();//这里之所以要弹出,是因为 //宽度=i-1(递增高度最大值对应下标) - 弹出当前元素后的栈顶高度 if(hists.empty()) { width = i;//表明0~i-1都是递增区间,长度为i } else { //这样理解i是第一个小于递增区间的下标。 i-1是递增区间的终止下标,那么hists.top()+1对应的是大于等于当前元素高度的起始结点下标 //宽度=终点-起点+1=i-1 - (hists.top() + 1) + 1 = i - 1 - hists.top() width = i - 1 - hists.top(); } area = heights.at(top) * width;//注意对应高度是top下标对应高度 if(area > maxArea) { maxArea = area; } } } //如果最后还有元素留在栈中,也必定是升序的,再计算一次 while(!hists.empty()) { top = hists.top(); hists.pop(); if(hists.empty()) { width = i; } else { width = i - 1 - hists.top(); } area = heights.at(top) * width; if(area > maxArea) { maxArea = area; } } return maxArea; } //从数组中选择最大的数,如果用线性时间选择,选择的是前k个数,时间复杂度为O(logN) //或者用堆来做,堆的实现应该是set,但是set你得先插入一遍数据,和直接遍历找出最小的一样。 int largestRectangleArea2(vector<int>& heights) { if(heights.empty()) { return 0; } int size = heights.size(); int maxArea = INT_MIN; int minHeight = INT_MAX; int area; int beg = -1; int end = -1; //最后一个位置i能够取到 for(int i = 0 ; i < size ; i++) { for(int j = i ; j < size ; j++) { minHeight = INT_MAX; for(int k = i ; k <= j; k++) { //求出最小高度 if(heights.at(k) < minHeight) { minHeight = heights.at(k); } } //求出面积 area = minHeight * (j - i + 1); if(area > maxArea) { maxArea = area; beg = i; end = j; } } } return maxArea; } }; void print(vector<int>& result) { if(result.empty()) { cout << "no result" << endl; return; } int size = result.size(); for(int i = 0 ; i < size ; i++) { cout << result.at(i) << " " ; } cout << endl; } void process() { vector<int> nums; int value; int num; Solution solution; vector<int> result; while(cin >> num ) { nums.clear(); for(int i = 0 ; i < num ; i++) { cin >> value; nums.push_back(value); } int result = solution.largestRectangleArea(nums); cout << result << endl; } } int main(int argc , char* argv[]) { process(); getchar(); return 0; }
相关文章推荐
- leecode 解题总结:38 Count and Say
- leecode 解题总结:32 Longest Valid Parentheses
- leecode 解题总结:40 Combination Sum II
- leecode 解题总结:39. Combination Sum
- leecode 解题总结:50. Pow(x, n)
- leecode 解题总结:46. Permutations
- leecode 解题总结:29 Divide Two Integers
- leecode 解题总结:28 Implement strStr()
- leecode 解题总结:42. Trapping Rain Water
- leecode 解题总结:15 3Sum
- leecode 解题总结:20. Valid Parentheses
- leecode 解题总结:19 Remove Nth Node From End of List
- leecode 解题总结:31. Next Permutation
- leecode 解题总结:25 Reverse Nodes in k-Group
- leecode 解题总结:53. Maximum Subarray
- leecode 解题总结:48. Rotate Image
- leecode 解题总结:23 Merge k Sorted Lists
- leecode 解题总结:35. Search Insert Position
- leecode 解题总结:45. Jump Game II
- leecode 解题总结:27 Remove Element