代码随想录算法训练营day62 | 42. 接雨水、84.柱状图中最大的矩形

42. 接雨水

暴力解法

遍历每根柱子(第一个和最后一个不需要遍历,因为不可能存住水),找到当前柱子的左边最高柱子lHeight,右边最高柱子rHeight,当前柱子能存的水为min(min(lHeight, rHeight) - 当前柱子的高度, 0)

class Solution:def trap(self, height: List[int]) -> int:result = 0for i in range(1, len(height)-1):leftHeight = height[i]rightHeight = height[i]for j in range(i):leftHeight = max(leftHeight, height[j])for j in range(i+1, len(height)):rightHeight = max(rightHeight, height[j])result += min(leftHeight, rightHeight) - height[i]return result

会超时

双指针解法

是对暴力解法的优化,暴力法在求当前柱子的左右最高的柱子时都会遍历一遍数组,而我们可以提前计算每个柱子的左右最高的柱子,存储起来。

如何求每个柱子的左右最高的柱子?其实和暴力法一样,左右最高的柱子如果比height[i]低或相等,肯定是存不在水的,因此可以初始化为height[i],即本方法中可以和本身也比较一次高度

  • 从左向右遍历:maxLeft[i] = max(height[i], maxLeft[i - 1]);
  • 从右向左遍历:maxRight[i] = max(height[i], maxRight[i + 1]);
class Solution:def trap(self, height: List[int]) -> int:if len(height) <= 2:return 0maxLeftHeight = [0] * len(height)maxRightHeight = [0] * len(height)maxLeftHeight[0] = height[0]for i in range(1, len(height)):maxLeftHeight[i] = max(maxLeftHeight[i-1], height[i])maxRightHeight[-1] = height[-1]for i in range(len(height)-2, -1, -1):maxRightHeight[i] = max(maxRightHeight[i+1], height[i])result = 0for i in range(1, len(height)-1):result += min(maxLeftHeight[i], maxRightHeight[i]) - height[i]return result

单调栈解法

本题使用单调栈有如下几个问题:

  • 1、首先单调栈是按照行方向来计算雨水
  • 2、使用单调栈内元素的顺序
  • 从栈头(元素从栈头弹出)到栈底的顺序应该是从小到大的顺序。
  • 3、遇到相同高度的柱子怎么办?遇到相同的元素,更新栈内下标,就是将栈里元素(旧下标)弹出,将新元素(新下标)加入栈中。
  • 4、栈里要保存什么数值?栈里就存放下标就行

三种情况

  • 情况一:当前遍历的元素(柱子)高度小于栈顶元素的高度 height[i] < height[st.top()]
  • 情况二:当前遍历的元素(柱子)高度等于栈顶元素的高度 height[i] == height[st.top()]
  • 情况三:当前遍历的元素(柱子)高度大于栈顶元素的高度 height[i] > height[st.top()]

先将下标0的柱子加入到栈中,st.push(0);。 栈中存放我们遍历过的元素,所以先将下标0加进来。然后开始从下标1开始遍历所有的柱子,for (int i = 1; i < height.size(); i++)。

如果当前遍历的元素(柱子)高度小于栈顶元素的高度,就把这个元素加入栈中,因为栈里本来就要保持从小到大的顺序(从栈头到栈底)。

如果当前遍历的元素(柱子)高度等于栈顶元素的高度,要更新栈顶元素,因为遇到相相同高度的柱子,需要使用最右边的柱子来计算宽度。

如果当前遍历的元素(柱子)高度大于栈顶元素的高度,此时就出现凹槽了。

class Solution:def trap(self, height: List[int]) -> int:if len(height) <= 2:return 0result = 0stack = [0]for i in range(1, len(height)):if height[i] < height[stack[-1]]:stack.append(i)elif height[i] == height[stack[-1]]:stack.pop()stack.append(i)else:while stack and height[i] > height[stack[-1]]:mid = stack.pop()if stack:result += (min(height[stack[-1]], height[i]) - height[mid]) * (i-stack[-1]-1)stack.append(i)return result

如果当前遍历的元素(柱子)高度等于栈顶元素的高度,可以不更新栈顶元素,直接入栈即可。后续计算出栈逻辑时,因为凹槽左边的值和当前值相同,计算值为0,和更新栈顶后结果一致。简化版代码就是这个逻辑

还有一个要注意的点:

原始的时候0入栈了,后来无论怎么操作最后当前元素都会入栈,栈内至少有一个元素,所以不需要判断栈内是否存在元素。

为什么当前元素大于栈顶元素的时候会检查?因为while语句下弹出元素,可能不止一个,因此需要判断。

精简版

class Solution:def trap(self, height: List[int]) -> int:if len(height) <= 2:return 0result = 0stack = [0]for i in range(1, len(height)):while stack and height[i] > height[stack[-1]]:mid = stack.pop()if stack:result += (min(height[stack[-1]], height[i]) - height[mid]) * (i-stack[-1]-1)stack.append(i)return result

84. 柱状图中最大的矩形

暴力解法

找到每根柱子左边和右边第一个小于当前柱子高度的 w = right - left - 1; h = heights[i]; result = max(result, w * h);

双指针解法

是对暴力解法的优化,和接雨水有差别,在求每根柱子左边和右边第一个小于当前柱子高度,不是直接和前一个进行比较,而是使用while不断迭代。数组中存储的是索引。

class Solution:def largestRectangleArea(self, heights: List[int]) -> int:leftMin = [0] * len(heights)rightMin = [0] * len(heights)leftMin[0] = -1for i in range(1, len(heights)):j = i - 1while j != -1 and heights[j] >= heights[i]:j = leftMin[j] leftMin[i] = jrightMin[-1] = len(heights)for i in range(len(heights)-1, -1, -1):j = i + 1while j != len(heights) and heights[j] >= heights[i]:j = rightMin[j]rightMin[i] = jresult = 0for i in range(len(heights)):result = max(result, heights[i] * (rightMin[i] - leftMin[i] - 1))return result

单调栈

因为本题是要找每个柱子左右两边第一个小于该柱子的柱子,所以从栈头(元素从栈头弹出)到栈底的顺序应该是从大到小的顺序

输入数组首尾各补上一个0(与接雨水不同的是,本题原首尾的两个柱子可以作为核心柱进行最大面积尝试)

class Solution:def largestRectangleArea(self, heights: List[int]) -> int:heights.insert(0, 0)heights.append(0)stack = [0]result = 0for i in range(1, len(heights)):if heights[i] > heights[stack[-1]]:stack.append(i)elif heights[i] == heights[stack[-1]]:stack.pop()stack.append(i)else:while stack and heights[i] < heights[stack[-1]]:mid = stack.pop()if stack:result = max((i - stack[-1] - 1) * heights[mid], result)stack.append(i)return result

精简版,stack不可能为空,因为数组第一个元素为0,不可能有比0还小的值,题目规定heights大于等于0, 因此第一个元素一定在stack中,不需要判断stack为空

class Solution:def largestRectangleArea(self, heights: List[int]) -> int:heights.insert(0, 0)heights.append(0)stack = [0]result = 0for i in range(1, len(heights)):while heights[i] < heights[stack[-1]]:mid = stack.pop()result = max((i - stack[-1] - 1) * heights[mid], result)stack.append(i)return result

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/32538.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mediasoup专栏介绍

mediasoup专栏介绍 mediasoup基础概览网络编程-libuv介绍mediasoup源码分析-v2和v3版本差异mediasoup日志模块mediasoup源码分析(一)编译及部署mediasoup源码分析(二)--worker启动golang实现mediasoup的tcp服务及channel通道mediasoup源码分析(三)channel创建及信令交互mediaso…

ARM功耗管理软件之WFIWFE

安全之安全(security)博客目录导读 思考&#xff1a;功耗管理软件栈及示例&#xff1f;WFI&WFE&#xff1f;时钟&电源树&#xff1f;DVFS&AVS&#xff1f; ARM功耗管理精讲与实战汇总参见&#xff1a;Arm功耗管理精讲与实战

java中Object和json相互转换的方式

1.org中jackson转换json,springboot中内置jackson ObjectMapper onew ObjectMapper(); List<>listnew ArrayList(); String jonso.writeAsValueString(list); 2.alibaba中fastjson转换成json GetMapping("/test")public TbUser testHttpClient(){String url…

Day11 —— 大数据技术之Spark

Spark快速入门系列 Spark的概述什么是Spark&#xff1f;Spark的主要特点Spark的主要组件 Spark安装Spark三种运行模式Spark Standalone架构Spark Standalone的两种提交方式Spark On YARN架构 RDD算子转化算子行动算子 Spark RDDRDD的创建从对象集合创建RDD从外部存储创建RDD Sp…

[C/C++][VsCode]使用VsCode在Linux上开发和Vscode在线调试

目录 0. 前言1. win10上搭建环境Linux环境2.编写makefile3.怎么在线调试结语 0. 前言 在开发中&#xff0c;可以一边开发一边调试&#xff0c;这样可以大大的减少bug&#xff1b;但是正常来说一个大点的项目&#xff0c;是不太可能单步调试的&#xff0c;因为一般都是用make或…

java打印金字塔paremid和空心金字塔

java打印金字塔 首先确定每行打印几个空格&#xff0c;在确定每行打印几个* 设总层数为layers&#xff0c;当前层数为i。 则每行打印空格数layers-i&#xff0c;每行打印星号数2*i-1 import java.util.Scanner;public class Paremid{public static void main(String[] args) …

基于Pico和MicroPython点亮ws2812彩色灯带

基于Pico和MicroPython点亮ws2812彩色灯带 文章目录 基于Pico和MicroPython点亮ws2812彩色灯带IntroductionPracticeConclusion Introduction 点亮发光的LED灯是简单有趣的实验&#xff0c;点亮多个ws2812小灯串联起来的灯带&#xff0c;可对多个彩色小灯进行编程&#xff0c;…

夏季城市内涝防治:视频汇聚系统智能AI技术助力城市自然灾害应急管理

据新闻报道&#xff0c;6月19日至20日&#xff0c;受强降雨影响&#xff0c;广西桂林城区及周边等地出现今年入汛以来持续时间最长、累计降水量最大、影响范围最广、致灾风险最高的暴雨天气过程&#xff0c;导致桂林市区多处发生洪水内涝&#xff0c;房屋被淹、道路受阻、人员被…

ES全文检索支持繁简和IK分词检索

ES全文检索支持繁简和IK分词检索 1. 前言2. 引入繁简转换插件analysis-stconvert2.1 下载已有作者编译后的包文件2.2 下载源码进行编译2.3 复制解压插件到es安装目录的plugins文件夹下 3. 引入ik分词器插件3.1 已有作者编译后的包文件3.2 只有源代码的版本3.3 安装ik分词插件 4…

【pytorch04】创建Tensor

numpy中的数据创建tensor 数据已经在numpy中了&#xff0c;将numpy中的数据转到tensor中来&#xff0c;因为我们将使用tensor在GPU上进行加速运算 从NUMPY导入的FLOAT其实是DOUBLE类型 list中的数据创建tensor FloatTensor()和大写的Tensor()接收的是shape&#xff08;即数据的…

Python-算法编程100例-前缀和双指针(入门级)-最长的指定瑕疵度的元音子串

题目描述&#xff1a; 元音字符为“aeiouAEIOU” 给定一个字符串&#xff0c;求字符串中满足指定瑕疵度的最长元音子串的长度。元音子串为字符串中开头和结尾都是元音字符的字符串&#xff0c;瑕疵度为子串中非元音字符的个数。 题目分析&#xff1a; 1、直接使用双指针&am…

JAVA学习过程中遇到的问题

前言 记录学习过程中遇见的各种问题。希望对你有帮助。 目录 前言 1、新建maven项目时&#xff0c;archetype项目骨架加载慢 2、maven的pop.xml添加依赖项无法检测到 3、java: 无效的目标发行版: 20 4、idea添加maven依赖太慢 5、CTRLCV复制粘贴太慢 6、Swagger写接口文…

5. 最长回文子串(leetcode)

5. 最长回文子串&#xff08;leetcode&#xff09; 题目描述 给你一个字符串 s&#xff0c;找到 s 中最长的回文子串 示例1 输入&#xff1a;s “babad” 输出&#xff1a;“bab” 解释&#xff1a;“aba” 同样是符合题意的答案。 示例2 输入&#xff1a;s “cbbd” 输出&a…

SD卡无法读取?数据恢复全攻略!

SD卡无法读取问题描述 在日常使用电子设备时&#xff0c;我们有时会遇到SD卡无法读取的情况。当插入SD卡后&#xff0c;设备可能无法识别或访问其中的数据&#xff0c;这给我们带来了诸多不便。SD卡无法读取&#xff0c;意味着存储在卡中的重要文件、照片和视频等资料可能面临…

NLP基础知识——文本处理、张量表示、文本数据分析

文本分词 jieba分词 繁体、简体都可以 #精确模式分词 import jieba content我来工作爱生活爱拉芳爱学习喜欢跳舞 jieba.lcut(content,cut_allFalse) #全模式分词 jieba.lcut(content,cut_allTrue) #搜索引擎模式 jieba.lcut_for_search(content) #自定义字典dict jieba.load_…

Java中的编译时与运行时注解

Java中的编译时与运行时注解 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 注解&#xff08;Annotation&#xff09;是Java语言的一项重要特性&#xff0c;广…

数学建模---包汤圆问题引发的思考

1.前言 &#xff08;1&#xff09;虽然我学习这个数学建模已经很长一段时间了&#xff0c;但是我认为自己始终是一个门外汉&#xff0c;只是学习了一下这个基本的建模软件使用方法&#xff0c;以及一些相关的知识&#xff0c;虽然参加了一次这个电工杯的比赛&#xff0c;但是这…

1.Triangle

一、你好&#xff0c;三角形 在OpenGL中&#xff0c;任何事物都在3D空间中&#xff0c;而屏幕和窗口却是2D像素数组&#xff0c;这导致OpenGL的大部分工作都是关于把3D坐标转变为适应你屏幕的2D像素。 3D坐标转为2D坐标的处理过程是由OpenGL的图形渲染管线&#xff08;Graphi…

Linux 下判断一个字符串ip是否合法

Linux 下判断一个字符串ip是否合法 C regexQt C ip是否合法参考 C regex #include <iostream> #include <regex> #include <string>bool is_valid_ip(std::string ip_str) {// 定义IPv4地址正则表达式//std::regex ipv4_regex("^([01]?[0-9]?[0-9]|2…

SQL中的DISTINCT用法总结

SQL中的DISTINCT用法总结 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 1. DISTINCT的基本概念 在SQL中&#xff0c;DISTINCT是一种用于去除查询结果中重复行…