数据结构——栈——求直方图最大面积

原题描述

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 height = [2,1,5,6,2,3],
return 10.

简单的说,给出一个直方图,求里面可以画出的最大的矩形的面积

动态规划解题思路

1、求出左数组:左数组的定义为,里面存放,从当前数组下标对应位置尽可能的往左走(前面的元素一定要比自己高),最左边所对应的元素。

2、求出右数组:定义和左数组相同,但是方向向右。

3、利用左右数组和每个位置的高度求出面积的最大值。

这样讲我自己都觉得抽象,还是由图形来说明。

总结一下这个算法的思想:假设当前高度x直方向左走最多走到那里,向右最多走到那里,向左右走的时候都能走比它高的,因为和低的不能组成矩形。

然后就是当前高度下最长的矩形了,然后计算每个高度下最大的矩形就能得到最大值了。

其中利用动态规划思想的地方是在:向左走的时候,如果前一个元素比你高,那么你可以利用前一个元素已经求出的左数组中的值从这个值直接再向前找。

举例来说:165432,现在3的左数组已经求出来的是【2】也就是下标为2的数字6,当要求2对应的左数组的值,因为3大于2,所以你可以直接利用3左数组中的值【2】因为大于3肯定大于2,所以可以瞬间往前走好几步。

如果还是不理解,那就看看代码吧。

动态规划解题代码

/**
*求直方图最大面积-dp
**/ 

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>

using namespace std;

//数组元素个数
int n=6;
//保存直方图的高度 (前后用一个-1标记)
int high[8]={-1,2,1,5,6,2,3,-1};
//定义左右数组
int leftArray[8]={-1,0,0,0,0,0,0,-1};
int rightArray[8]={-1,0,0,0,0,0,0,-1};

void getLeft()
{
    for(int i=1;i<=n;i++)
    {
        int k = i;
        while(high[i] <= high[k-1])
            k = leftArray[k-1];
        leftArray[i] = k;
    }
}

void getRight()
{
    for(int i=n;i>=1;i--)
    {
        int k = i;
        while(high[i] <= high[k+1])
            k = rightArray[k+1];
        rightArray[i] = k;
    }
}

int getMax()
{
    int maxArea = 0;
    for(int i=1;i<=n;i++)
    {
        int temp=0;
        temp = (rightArray[i]-leftArray[i]+1) * high[i];

        if(temp > maxArea)
            maxArea = temp;
    } 

    return maxArea;
}

int main()
{
    //求左数组
    getLeft();
    //求右数组
    getRight();
    //求最大值
    cout<<getMax()<<endl;
    return 0;
}

利用栈解题思路

下面是栈的解题思路。巧妙的利用栈里计算全部可能的面积,求最大值。

利用栈解题的代码

/**
*求直方图最大面积-stack
**/ 

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <stack>

using namespace std;

//数组元素个数
int n=6;

//保存直方图的高度 (前后用一个-1标记)
int high[6]={2,1,5,6,2,3};

int main()
{
    int i=0, maxArea=0,tempArea=0,popNum=0;
    stack<int> map;

    for(i=0; i<n; i++)
    {
        if(map.empty() || high[i] > high[map.top()])
            map.push(i);
        else
        {
            popNum = map.top();
            map.pop();
            if(map.empty())
            {
                tempArea = i * high[popNum];
            }
            else
            {
                tempArea = (i-map.top()-1) * high[popNum];
            }
            if(tempArea > maxArea)
                maxArea = tempArea;
            i--;
        }
    }

    while(!map.empty())
    {
        popNum = map.top();
        map.pop();
        if(map.empty())
        {
            tempArea = n * high[popNum];
        }
        else
        {
            tempArea = (n-map.top()-1) * high[popNum];
        }
        if(tempArea > maxArea)
            maxArea = tempArea;
    }

    cout<<"max area = "<<maxArea<<endl;
    return 0;
}

总结和思考

个人认为其实dp的方式更容易让人理解一些,但是从代码量上面来说,确实用栈会快一些。

不够只能说下一次解题如果没有栈这个模版的话,比较容易写出的还是dp的方式。

另外说一下,虽然dp的方式有for循环嵌套while循环,但是还是能保证时间复杂度还是O(N),和栈的方式是相同的。

只能说栈这个方法确实很巧妙,所以要记录一下。

时间: 2024-07-28 15:52:29

数据结构——栈——求直方图最大面积的相关文章

数据结构--单调栈--求最大子矩阵的大小

求最大子矩阵的大小给定一个整型矩阵map, 其中的值只有0和1两种, 求其中全是1的所有矩形区域中, 最大的矩形区域为1的数量.例如:1 1 1 0其中, 最大的矩形区域有3个1, 所以返回3.再如:1 0 1 11 1 1 11 1 1 0其中, 最大的矩形区域有6个1, 所以返回6. 解:将其放到一个矩阵中,同时从第0行开始计算,以该行打底时,直方图的最大面积 如第0行,数组为[1, 0, 1, 1] 此时按照下面的求直方图最大面积. 然后以第1行打底,此时数组为[2, 1, 2, 2],同

poj 2082 Terrible Sets (数据结构 ——栈 STL)

 Terrible Sets Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 2999   Accepted: 1549 Description Let N be the set of all natural numbers {0 , 1 , 2 , . . . }, and R be the set of all real numbers. wi, hi for i = 1 . . . n are some elem

数据结构——栈——寻找下一个较大元素

题目描述 给出一个数组,向右寻找每一个元素的下一个较大的元素,没有更大的则为-1 举例 {4,6,1,3,2,5} 则求得的答案应为 {6,-1,3,5,5,-1} 题目分析 首先对于这样的题目,我们总是先想到最简单的,那么就是枚举,每次循环一个元素,不停的向右找就可以了.时间复杂度应该是n^2 但是这样肯定是不够用的. 然后我们考虑,这道题我们实际上遇到的问题是什么? 其实简单的说,这道题的意思是,在变化的数组中找到下一个较大的值. 难点在于,数组元素的变化,以及不是找最大值,而是找下一个较大

HDU 1022 Train Problem I (数据结构 —— 栈)

Problem Description As the new term comes, the Ignatius Train Station is very busy nowadays. A lot of student want to get back to school by train(because the trains in the Ignatius Train Station is the fastest all over the world ^v^). But here comes

基本数据结构-栈的实现及其运用

概述:数据结构是用来实现动态集合的方式.动态集合有两个要素,一是动态集合中的元素,二是动态集合上的操作如search(s,k):其中s为给定的集合,k为所要查询的关键字.Insert(s,k),delete,maximun,minimum,successor,predecessor等. 这里介绍几种简单的数据结构:栈,队列,链表,有根树. 一.栈 栈有一定限制的表,元素的插入和删除只能在表头进行,栈虽然缺少鲁棒性,但是更有效,并且很容易应用,栈后进先出.基本的操作包括进栈PUSH,出栈pop,判

数据结构——栈和队列相关算法实现

数据结构栈和队列的基本算法实现 限定性线性表--栈 栈的定义 栈作为一种限定性的线性表,是将线性表的插入和删除操作限制为仅在表的一端进行. 基本算法演示 /* 栈的常见操作: 1.初始化栈 2.元素进栈 3.元素出栈 4.栈的遍历 5.判断栈是否为空栈 6.清空整个栈 */ # include <stdio.h> # include <stdlib.h> typedef struct Node { int date; struct Node * pNext; }NODE,* PNO

南阳OJ-2 括号配对 (数据结构-栈的应用)

括号配对问题 时间限制:3000 ms  |  内存限制:65535 KB 难度:3 描述 现在,有一行括号序列,请你检查这行括号是否配对. 输入 第一行输入一个数N(0<N<=100),表示有N组测试数据.后面的N行输入多组输入数据,每组输入数据都是一个字符串S(S的长度小于10000,且S不是空串),测试数据组数少于5组.数据保证S中只含有"[","]","(",")"四种字符 输出 每组输入数据的输出占一行,

JAVA求圆的面积

import java.text.DecimalFormat;import java.util.Scanner; public class TheAreaOfCircle { public static void main(String[] args) { /*问题描述 给定圆的半径r,求圆的面积. 输入格式 输入包含一个整数r,表示圆的半径. 输出格式 输出一行,包含一个实数,四舍五入保留小数点后7位,表示圆的面积. 说明:在本题中,输入是一个整数,但是输出是一个实数. 对于实数输出的问题,请

c++入门第一天(求圆的面积)

看了一会书,发现C++和C虽然于发上相似,但是解决问题的方式还是不一样的,毕竟面向对象和面向过程是两种不同的思维方式.下面就通过一个求圆的面积的例子,比较C和C++的不同. 需求:输入圆的半径,求解圆的面积 使用C语言来解决:1.定义两个变量半径r.面积s;  2.输入半径;  3.打印结果. 以下是源代码: #include <stdio.h> int main01() { double r, s; //定义变量圆和半径 printf("请输入圆的半径:"); scanf