当前位置: 首页 > ds >正文

代码随想录|单调栈|04接雨水

leetcode:42. 接雨水 - 力扣(LeetCode)

题目

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

示例 1:

输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 

示例 2:

输入:height = [4,2,0,3,2,5]
输出:9

提示:

  • n == height.length
  • 1 <= n <= 2 * 104
  • 0 <= height[i] <= 105

思路

听说这是字节最简单的题。

方法1:前后缀分解

对于每个柱子i,左边的高度取决于左边的最大高度lMax,右边的高度取决于右边的最大高度rMax

然后存储的水量为min(lMax,rMax)-height(i)。

所以可以设计一个前缀数组pre_max、后缀数组suf_max

pre_max[i]记录第i个柱子左边的最大高度

suf_max[i]记录第i个柱子右边的最大高度

从题目给的图可以看出,两个端点是一定接不了雨水的,因为要不是左边没有,要不就是右边没有,所以把两个端点初始化为height自己,可以保证min(lMax,rMax)-height(i)是0。

class Solution
{
public:int trap(vector<int> &height){int n=height.size();vector<int> pre_max(n);vector<int> suf_max(n);pre_max[0]=height[0];suf_max[n-1]=height[n-1];int result=0;for(int i=1;i<n;i++){pre_max[i]=max(height[i],pre_max[i-1]);}for(int i=n-2;i>=0;i--){suf_max[i]=max(height[i],suf_max[i+1]);}for(int i=0;i<n;i++){result += min(pre_max[i],suf_max[i])-height[i];}return result;}
};

方法2:单调栈

下面用单调栈来解决这个题,注意是按照行来看的,我们要计算的是宽度。

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

所以在==这种情况下,跟之前不同,需要先把栈顶弹出,然后把新的放进去作为栈顶。

if (height[i] == height[st.top()]) { // 例如 5 5 1 7 这种情况st.pop();st.push(i);
}

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

取栈顶元素,将栈顶元素弹出,这个就是凹槽的底部,也就是中间位置,下标记为mid,对应的高度为height[mid](就是图中的高度1)。

此时的栈顶元素st.top(),就是凹槽的左边位置,下标为st.top(),对应的高度为height[st.top()](就是图中的高度2)。

当前遍历的元素i,就是凹槽右边的位置,下标为i,对应的高度为height[i](就是图中的高度3)。

有了这3个元素,就可以求出这个凹槽能够接多少水:

雨水高度 = min(height[st.top()], height[i]) - height[mid]

雨水宽度 = i - st.top() - 1      (只求中间凹槽宽度,所以还要-1)

然后把宽度和高度乘起来,就是这个凹槽的雨水,最后总得雨水加起来即可。

class Solution
{
public:int trap(vector<int> &height){int n = height.size();stack<int> st;st.push(0);int sum = 0;for (int i = 1; i < n; i++){if (height[i] < height[st.top()]){st.push(i);}else if (height[i] == height[st.top()]){st.pop();st.push(i);}else{while (!st.empty() && height[i] > height[st.top()]){int mid = st.top();st.pop();if (!st.empty()){int h = min(height[st.top()], height[i]) - height[mid];int w = i - st.top() - 1;sum += h * w;}}st.push(i);}}return sum;}
};

总结

这个题用单调栈反而觉得麻烦,再就是这里是按照行,横向来看这个柱状图,很不容易看懂,比较直观的方法是前缀和、后缀和那个方法。

参考资料

 代码随想录

http://www.xdnf.cn/news/14780.html

相关文章:

  • SpringBoot中使用表单数据有效性检验
  • UE5 闪烁的光斑
  • Lamp和友点CMS一键部署脚本(Rocky linux)
  • 75、单元测试-嵌套测试
  • 揭开 Git 裸仓库的神秘面纱:`git clone --mirror` 详解与使用指南
  • Windows电脑数据恢复终极指南:从原理到实战
  • 《去哪儿网Redis高并发实战:从问题定位到架构升级》
  • redis如何使用IO多路复用
  • 黑马python(十三)
  • Windows11 无法发现局域网内设备解决方法
  • SQL Server基础语句4:数据定义
  • 【C++开发】CMake构建工具
  • VBA基础之对象
  • CentOS 7.9 系统安装 Percona XtraBackup(含 xtrabackup 和 innobackupex 工具)的详细步骤
  • 深入剖析Flink内存管理:架构、调优与实战指南
  • 如何仅用AI开发完整的小程序<4>—小程序页面创建与删除
  • Kafka动态配置深度解析
  • Azure Devops
  • JMeter API 并发性能测试计划JMX文件解析
  • Elasticsearch、Faiss、Milvus在向量索引实现上的核心差
  • Redis 8.0向量库 vs 传统向量数据库:大模型知识库开发选型全指南
  • 华为公布《鸿蒙编程语言白皮书》V1.0 版:解读适用场景
  • HarmonyOS NEXT端侧工程调用云侧能力实现业务功能
  • 跨个体预训练与轻量化Transformer在手势识别中的应用:Bioformer
  • 什么是跨域问题?后端如何解决跨域问题?
  • rent8_wechat-最常用出租屋管理系统-微信小程序
  • 计算机网络第九章——数据链路层《流量控制和可靠传输》
  • Web攻防-XSS跨站Cookie盗取数据包提交网络钓鱼BEEF项目XSS平台危害利用
  • 【分布式理论】读确认数与写确认数:分布式一致性的核心概念
  • 吴恩达:从斯坦福到 Coursera,他的深度学习布道之路