LeetCode_直方图最大面积(Largest Rectangle in Histogram)

LeetCode: Largest Rectangle in Histogram(直方图最大面积) 具体的题目描述为: 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 wher 阅读详情

一、题目

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.1.1

LeetCode 84题:Largest Rectangle in Histogram,给定一个直方图(下图a),求直方图中能够组成的所有矩形中,面积最大为多少。对于图a来说,我们很容易看出来面积最大的矩形为高度为5和6的直方图组成的矩形(图b隐形部分),其面积为5 * 2 = 10。


二、解题

1.感想

如果就对于图片的示例而言,许多人一看就知道答案了,压根就不需要太多的思考,可是正是因为这种定性的思考,让我们慢慢没法“知其所以然”,也让我们慢慢失去了举一反三的思考方式,就图片的示例而言,之所以我们一看就能看出答案,是因为示例的例子数据太少了,如果数据很多的时候我们能一看就看出答案吗?所以无论面对什么样的题目,我们都不能放弃“知其所以然”,从根本解决问题。

2.暴力搜索

这道题目一个显而易见的解决方法就是暴力搜索:找出所有可能的矩形,然后求出面积最大的那个。要找出所有可能的矩形,只需要从左到右扫描每个立柱,然后以这个立柱为矩形的左边界(假设为第i个),再向右扫面,分别以(i+1, i+2, n)为右边界确定矩形的形状。

这符合我们本能的思考过程:要找出最大的一个,就先列出所有的可能,比较大小后求出最大的那个。然而不幸的是,本能的思考过程通常是简单粗暴而又低效的,就这个题目来说,时间复杂度为N^2 。

3.使用动态规划

用left[i]表示第i个柱子可以最多向左延伸至第left[i]个柱子,形成一个矩形,right[i]则表示向右延伸。遍历两次,分别计算出这两个数组。

再遍历一次,即可求出所有的柱子可以形成的最大的矩形面积。为了减少边界的判断,可以使用哨兵,在两端添加两个柱子高度都为-1.

public class LargestRectangle {

    public static void main(String[] args) {
        int height[] = { 2, 1, 5, 6, 2, 3 };
        int ans = getMaxRectangle(height);
        // lift[]=[0,1,1,3,4,3,6] right[]=[0,1,6,4,4,6,6]
        System.out.println("最大的面积位:" + ans);
    }

    /**
     * 遍历每个柱子可以组成的最大面积
     * 
     * @param heights
     * @return 最大的面积
     */
    public static int getMaxRectangle(int heights[]) {
        int ans = 0;
        int n = heights.length;
        int left[] = new int[n + 1];
        int right[] = new int[n + 1];
        processLR(heights, left, right);
        for (int i = 1; i <= n; i++) {
            int tmp = (right[i] - left[i] + 1) * heights[i - 1];
            if (ans < tmp)
                ans = tmp;
        }
        return ans;
    }

    /**
     * 初始化左右两个数组
     * 
     * @param heights
     * @param left
     * @param right
     */
    public static void processLR(int heights[], int left[], int right[]) {
        int n = heights.length;
        // 用临时数组,设置两个哨兵
        int tempArr[] = new int[n + 2];
        tempArr[0] = -1;
        for (int i = 1; i <= n; i++)
            tempArr[i] = heights[i - 1];
        tempArr[tempArr.length - 1] = -1;

        // 用left[i]表示第i个柱子可以最多向左延伸至第left[i]个柱子
        for (int i = 1; i <= n; i++) {
            int k = i;
            while (tempArr[i] <= tempArr[k - 1])
                k = left[k - 1];
            left[i] = k;
        }

        // 用right[i]表示第i个柱子可以最多向右延伸至第right[i]个柱子
        for (int i = n; i > 0; i--) {
            int k = i;
            while (tempArr[i] <= tempArr[k + 1])
                k = right[k + 1];
            right[i] = k;
        }
    }
}

运行的结果:

2.3.1

4.巧妙使用栈

在网上发现另外一个使用一个栈的O(n)解法,代码非常简洁,栈内存储的是高度递增的下标。对于每一个直方图高度,分两种情况。1:当栈空或者当前高度大于栈顶下标所指示的高度时,当前下标入栈。否则,2:当前栈顶出栈,并且用这个下标所指示的高度计算面积。而这个方法为什么只需要一个栈呢?因为当第二种情况时,for循环的循环下标回退,也就让下一次for循环比较当前高度与新的栈顶下标所指示的高度,注意此时的栈顶已经改变由于之前的出栈。

public class largestRectangleArea {

    public static void main(String[] args) {
        int height[] = { 2, 1, 5, 6, 2, 3 };
        int ans = largestRectangleArea(height);
        System.out.println("最大的面积位:" + ans);
    }

    // O(n) using one stack
    public static int largestRectangleArea(int[] height) {
        // Start typing your Java solution below
        // DO NOT write main() function
        int area = 0;
        java.util.Stack<Integer> stack = new java.util.Stack<Integer>();
        for (int i = 0; i < height.length; i++) {
            if (stack.empty() || height[stack.peek()] < height[i]) {
                stack.push(i);
            } else {
                int start = stack.pop();
                int width = stack.empty() ? i : i - stack.peek() - 1;
                area = Math.max(area, height[start] * width);
                i--;
            }
        }
        while (!stack.empty()) {
            int start = stack.pop();
            int width = stack.empty() ? height.length : height.length
                    - stack.peek() - 1;
            area = Math.max(area, height[start] * width);
        }
        return area;
    }
}

这是看到别人的推演过程,之前看到,就添加到笔记了,没有原著的地址,所以没法标明出处:

一个思维历程

那么这个算法真的就是我等凡夫俗子不能想出来的?难道我们只能仰望高山,恨自己智商不高?我还真不服气呢,于是又静下心去思考这个问题。

这次我们不从已知条件推结果,而直接从结论入手,就是说假设现在已经找到了面积最大的那个矩形。接着我们来分析该矩形有什么特征,然后可以用下面两种方法之一来缩减问题的规模(因为这两种方法都不用找出所有的矩形一一比较)。

找出满足这些特征的矩形,面积最大的矩形肯定是其中之一;
排除那些不满足这些特征的矩形,面积最大的矩形在剩下的那些矩形里面。
为了使考虑情况尽可能全面,画了许多直方图,防止使用原题目图片可能存在的一些特定假设,其中一个直方图如下图:

2.4.1

题目情况分析

通过不断地对多个直方图的观察,发现面积最大的那个矩形好像都包含至少一个完整的bar,那么这条规律适用于所有的直方图吗?我们用反证法来证明,假设某个最大矩形中每个竖直块都是所在的bar的一小段,那么这个矩形高度增加1后仍然是一个合法的矩形,但新的矩形面积更大,与假设矛盾,所以面积最大的矩形必须至少有一个竖直块是整个bar。

至此我们找到了面积最大矩形的一个特性:各组成竖直块中至少有一个是完整的Bar。有了这条特性,我们再找面积最大的矩形时,就有了一个比较小的范围。具体来说就是针对每个bar,我们找出包含这个bar的面积最大的矩形,然后只需要比较这N个矩形即可(N为bar的个数)。

那么问题又来了,如何找出“包含某个bar的面积最大的矩形呢”?对于上面的直方图,包含下标为4的bar的最大矩形如下图橘黄色部分:

2.4.2

局部最大矩形

简单观察一下,就会发现要找到包含某个bar的最大矩形其实很简答,只需要找到高度小于该bar的左、右边界即可,上图中分别是下标为1的bar和下标为10的bar。

至此问题已经变为“对于给定的bar,如何确定高度比它小的左、右边界”。其实求左边界和右边界是同样的求法,下面我们考虑求每个bar的左边界。最直接的思路是对于每个bar,扫面其前面所有的bar,找出最后一个高度小于它的bar,这样的话时间复杂度明显又是N^2 ,Holy Shit。

到这里似乎没有路可走了,但如果我们继续绞尽脑汁地去想,可能(或许你对栈理解的很深入,或许是你在一个类似的问题中用到了栈,当然你也可能想到动态规划的思想,那也是可行的)会联想到栈这一数据结构。用栈维护一个高度递增的bar的集合,也就是说栈底到栈顶部对应的bar的高度越来越大。那么对应一个刚读入的bar,我们只需要比较它的高度和栈顶对应bar的高度,如果当前bar比较高,则弹出栈顶元素继续比较,直到栈顶bar比它低或者栈为空。之后,将当前bar入栈,更新栈内的递增序列。

我们从左到右扫一遍得到每个bar对应的左边界,然后从右到左扫一遍得到bar的右边界。两次扫描过程中,每个bar都只有出栈、入栈操作,所以时间复杂度为O(N)。通过这样的预处理,即可以O(N)的时间复杂度得到每个bar的左右边界。之后对于每个bar求出包含它的最大面积,也即是由左右边界和bar的高度围起来的矩形的面积。再做N次比较,即可得出最终的结果。

这里先预处理用两个栈扫描两次得到左、右边界,再计算面积,是按照推导过程一步一步来的。当我们写完程序后,再综合看这个问题,可能会发现其实没必要这样分开来做,我们可以在扫描的同时,维护一个递增的栈,同时在“合适的”时候计算面积,然后更新最大面积。具体实现方法就是前面给出的那个神奇的算法,不过现在看来一点也不神奇了,我们已经探索到了它背后的思维历程。

当然,条条道路通罗马,上面思维过程只是其中一条通往解决方案的路径,你可能以另一种思维过程找到了答案。不过,我们上面的整个推导过程没有涉及一些类似“神谕”的启发,只是一些简单的方法:比如从结论推导、反证法、归纳总结、联想(可能联想到栈有点难)等,因此每个人都可以学会,并且很容易被大脑记住。值得注意的是,我们的整个思考过程并不简简单单地跟上面写的那样是线性的,它更可能是树形的,只是我们剪去了那些后来证明行不通的枝。

Demo:http://download.youkuaiyun.com/detail/two_water/9670562


三、思考

最后奉上看到别人写的东西,略有感想,故分享。

3.1.1

无人机核心部件解析:从机架到飞控的全面指南 本文全面解析无人机的核心部件,从机架材质选择到飞控系统调参,提供专业指南。重点介绍碳纤维机架、无刷电机搭配、锂聚合物电池管理及飞控传感器配置,帮助读者掌握无人机组装与优化的关键技术,适用于航拍、测绘、农业植保等多种应用场景。 阅读详情

相关推荐

JPA - @MappedSuperclass - 基类注解

目录前言代码示例 前言 @MappedSuperclass注解一般作为基类的注解,表眀该类是映射的超类,继承于它的子类实体在映射时会自动添加到子类实体的对应数据库表中,用于共同的属性代码复用和模型分离。 代码示例 BaseEntity.java import lombok.Getter; import lombok.Setter; import javax.persistence.MappedSuperclass; import java.util.Date; @Getter @Setter @Ma

Maggieq8324的博客 2065

直方图之回顾

频数直方图:高度代表频数密度(频数/组距),此时组距为1,则面积代表频数频率直方图:高度代表频率密度(频率/组距),面积代表频率!!

m0_51984816的博客 3366

Hyper-V虚拟机 安装 银河麒麟V10桌面版

如何在windows 11 Hyper-V 虚拟机中 安装 银河麒麟V10桌面版。

m0_46756112的博客 3418

直方图 (Histogram)

用矩形的面积来表示频数分布的图形 在直角坐标中,用横轴表示数据分组,纵轴表示频数密度,各组与相应的频数就形成了一个矩形,即直方图 直方图下的总面积等于总频数(或1) 适用于定距变量 ...

6285

scratch航天梦主题课程作品分享,包含ppt、素材包

而今年多国都将发射探测器尝试登陆月球,2023年或将称为“登月年”,请大家发挥创新思维,以“星辰大海”为创作主题,搜集相关信息 、展开联想,为实现升空 、探测 、取样贡献创意!即使去淘宝买的素材,也要从百度网盘,但素材太多大了或者太多文件,也要充值百度网盘超级会员才能保存,提高下载速度。同学们大家好,今天我们就要开始航天主题-嫦娥五号探月工程系列的编程课程了,不仅可以学习到很多航天知识,了解本次嫦娥五号的发射历程,还能让我们用编程遨游太空呢。即使下载了,也要上传,不是特别方便,尤其是不好查找。

少儿编程吕口口 2481

【AutoDL + Langchain-Chatchat】从零构建高效本地 RAG 知识库问答系统:实战保姆级教程(含避坑指南)

本文详细阐述如何在AutoDL云平台,如何利用Langchain-Chatchat构建高效的本地RAG知识库问答系统,并深入解析RAG架构。从环境搭建到实战部署,从问题排查到性能优化,提供一份全面实用的指南,助力开发者快速构建智能问答应用。

拾光夕拾的博客 1803

leetcode_question_85 Largest Rectangle in Histogram

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

ZkvIA的博客 1万+

浅谈python反序列化漏洞

0x01 python序列化与反序列化 Python 的序列化和反序列化是将一个类对象向字节流转化从而进行存储和传输,然后使用的时候再将字节流转化回原始的对象的一个过程。python中的序列化操作是通过pickle模块,而该模块主要包含l dumps将dict转化为str格式,loads将str格式转化为dict格式。 dump和load与文件操作结合起来, pickle.dump(obj, f...

Lethe's Blog 3220

描述性统计分析 | 直方图

直方图的详细讲解

weixin_42444823的博客 2774

C# 从数秒到毫秒:MySQL+Redis百万数据优化实战全解析

在处理百万级数据时,传统单体数据库常面临查询效率低下、数据库负载过高和用户体验差等问题。为解决这些性能瓶颈,可以采用MySQL分库分表、Redis缓存和异步统计的组合策略。 数据库分片:通过水平分表和分库实现,将单表数据分散到多个物理表或数据库实例中,降低单点负载。 Redis缓存:利用Redis缓存高频数据,减少数据库查询压力,提升响应速度。 异步统计:通过消息队列(如RabbitMQ)解耦统计任务,后台处理非实时任务,避免阻塞主流程。 这些优化策略能够显著提升系统性能,确保在高并发和大数据量场景下的稳定

墨夶的博客 852

使用 Python 爬取网易云音乐歌单数据(完整教程)

随着在线音乐平台的普及,网易云音乐(NetEase Cloud Music)凭借其个性化的推荐算法和丰富的用户互动,吸引了大量用户。网易云音乐的歌单中包含了丰富的音乐数据,包括歌曲名、歌手、专辑、播放量、评论数等信息。通过爬取这些数据,可以对音乐流行趋势进行分析,挖掘音乐推荐策略,甚至训练个性化推荐模型。网易云音乐的 API 并未官方开放,但开发者通过抓包和逆向分析,找到了若干可用接口。✅ 数据清洗与存储(CSV/数据库)✅ 网易云音乐 API 接口分析。✅ 网易云音乐接口解析。✅ 同步与异步爬取实现。

2201_76125261的博客 1372

LeetCode:Largest Rectangle in Histogram(直方图中最大矩形面积)

84. Largest Rectangle in Histogram 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.   Ab...

但行好事,莫问前程 957

在移动固态上安装ubuntu系统,重启后卡住报错:blk_update_request: I/O error, dev sda, sector ... op 0x0 (READ)如何解决?

🏆本文收录于 《全栈 Bug 调优(实战版)》 专栏。专栏聚焦真实项目中的各类疑难 Bug,从成因剖析 → 排查路径 → 解决方案 → 预防优化全链路拆解,形成一套可复用、可沉淀的实战知识体系。无论你是初入职场的开发者,还是负责复杂项目的资深工程师,都可以在这里构建一套属于自己的「问题诊断与性能调优」方法论,助你稳步进阶、放大技术价值 。

**My Coding Family** 1798

[LeetCode]—Largest Rectangle in Histogram 求直方图最大填充矩形面积

Largest Rectangle in Histogram

清水 977

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

LeetCode(084)-Largest Rectangle in Histogram(直方图最大矩形面积)

题目: 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 ea...

Fly_Fly_Zhang的博客 691

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

LeetCode 84. Largest Rectangle in Histogram(直方图中最大矩形面积)

题目描述:    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 ...

andersonxie的博客 2800

Largest Rectangle in Histogram (直方图中最大面积) 【leetcode】

题目: 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 wh

Havenoidea 的专栏 7296

LeetCode | Largest Rectangle in Histogram(直方图围城的最大矩形面积)

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 o

solar一抹阳光的专栏 1137

【LeetCode】84. Largest Rectangle in Histogram——直方图最大面积

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 b...

weixin_33973600的博客 82

4.1.3LeetCode: Largest Rectangle in Histogram(直方图最大面积)

http://www.cnblogs.com/avril/archive/2013/08/24/3278873.html 具体的题目描述为:   Given n non-negative integers representing the histogram's bar height where the width of each bar is 1, find the are

ZhikangFu的专栏 690

【leetcode每日刷题】Largest Rectangle in Histogram

https://leetcode.com/problems/largest-rectangle-in-histogram/ 求直方图中的最大矩形 从左到右找到最高的矩形,然后从右向左计算最大的面积。 class Solution(object): def largestRectangleArea(self, heights): """ :type h...

菜菜鸟的博客 173

leetcode栈--2、largest-rectangle-in-histogram(直方图最大面积)

题目描述 Givennnon-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 wi...

weixin_30820077的博客 115

最大矩形(Stack,Vector,Queue,Deque)

Largest Rectangle in Histogram:https://leetcode.com/problems/largest-rectangle-in-histogram/description/public int largestRectangleArea(int[] height) { int len = height.length; Stack&l...

heiheibupt的博客 215

Leetcode -- Maximal Rectangle

https://oj.leetcode.com/problems/maximal-rectangle/ Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing all ones and return its area  public int maximalRectan

chaochen1407的专栏 387

算法设计与分析第一周练习

题目 Given n non-negative integers a1, a2, …, an , where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find t...

Vilin的博客 281

Leetcode. Largest Rectangle in Histogram

1. 题解 题目 链接🔗:84. Largest Rectangle in Histogram 这道题和42. Trapping Rain Water有些相像,但是42题求的是能围住的最大面积,而本题求的是连成的矩阵的最大面积,因而在计算面积的方法上有些许不同。85. Maximal Rectangle就是在本题基础上的变式,通过一系列变化可以使用本题方法。 分析 简单分析可以知道最大矩形面积有两种情况: 当前矩形的高度heights[i] * 1 当前矩形的高度heights[i] * (向右第一个比

三明治文鱼的博客 7797
上一篇: 微信小程序学习(6)_配置详解
下一篇: Android 网络框架_常用的网络框架
Two_Water
博客等级 码龄12年 573粉丝 134原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值