IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> ★★[leetCode 42] 接雨水 总结 -> 正文阅读

[数据结构与算法]★★[leetCode 42] 接雨水 总结

解题思路

这道题有两种主要的思路,一种是按列计算接到的雨水总量,另一种是按行计算接到的雨水总量。

首先来看看如何按列计算雨水总量:

  1. 首先,首尾两列肯定是接不到雨水的,不用计算
  2. 其次,这一列什么情况下能够接到雨水呢?答案就是,这一列的左右两侧都存在比这一列更高的列,不然的话,这一列肯定是接不到雨水的。仔细想一想就能明白为什么。
  3. 如果这一列能够接到雨水,那么这一列的雨水数量是多少?其实就是,取左右两侧最高的列中较低的列,说起来比较拗口,就是取min(maxLeft,maxRight),用这个高度减去当前列的高度,就是当前列的雨水量
  4. 那么按照上述思路,从前往后遍历每一列,对于每一列,计算它这一列的雨水数即可。

代码

public class Solution {
    public int trap(int[] height) {
        int sum=0;
        //第一列和最后一列不用计算
        for (int i=1;i<height.length-1;i++){
        	//依次计算该列左右两侧最高的列
            int l=0,r=0;
            for (int j=i-1;j>=0;j--){
                l=Math.max(l,height[j]);
            }
            for (int k=i+1;k<height.length;k++){
                r=Math.max(r,height[k]);
            }
            //计算雨水
            if (Math.min(l,r)>height[i]){
                sum=sum+Math.min(l,r)-height[i];
            }
        }
        return sum;
    }
}

优化

对于上述思路,时间复杂度是O(n^2)。我们会发现,在每次计算这一列的左右两侧最大高度的时候,出现了重复的计算,导致了时间复杂度的提升。

那么有没有办法优化呢?

有!我们提前把每一列左右两侧的最大高度计算出来,存下来,用的时候直接来拿就好了。
计算这个最大高度的方法,可以用动态规划的思想,这样就可以把时间复杂度优化到O(n)

思路如下:

  1. dp数组的定义,定义maxLeft[i]为第i列左侧的最高高度,maxRight[i]为第i列右侧的最高高度。
  2. maxLeft从前往后遍历,maxLeft[i]=MAX(maxLeft[i-1],height[i]),
    maxRight[i]=MAX(maxRight[i+1],height[i])

其他步骤不变。

代码如下

public class Solution {
    public int trap(int[] height) {
        int[] maxLeft=new int[height.length];
        int[] maxRight=new int[height.length];
        maxLeft[0]=height[0];
        maxRight[height.length-1]=height[height.length-1];
        for (int i=1;i<height.length;i++){
            maxLeft[i]=Math.max(height[i],maxLeft[i-1]);
        }
        for (int j=height.length-2;j>=0;j--){
            maxRight[j]=Math.max(height[j],maxRight[j+1]);
        }
        int sum=0;
        for (int i=1;i<height.length-1;i++){
            int l=maxLeft[i],r=maxRight[i];
            if (Math.min(l,r)>height[i]){
                sum=sum+Math.min(l,r)-height[i];
            }
        }
        return sum;
    }
}

按行计算雨水总量

用单调栈的思想,来依次计算每一行的雨水总量,这个比较不好理解。

我们用一个单调栈来维护目前已经遍历过的列,栈顶到栈底是递减的,当遍历到新的列时,有以下3种情况:

  1. height[i]<height[top],新元素的值小于栈顶的元素值,那么可以把新元素直接加入栈中
  2. height[i]==height[top],新元素的值和栈顶元素一样大,那么更新栈顶元素的下标
  3. height[i]>height[top],新元素的值大于栈顶元素的值,这个栈顶的元素用top来代替,这时说明的top的左右两侧都有比它更高的列,top就是当前能接到雨水的部分的底座。那么当前部分的高度应该是多少呢?其实就是top左右两侧更高的列中较低的那一个,也就是此刻栈中的第二个元素j和当前遍历的元素i中较低的值。
    此时雨水的量就是(i-j-1)*MIN(height[j],height[i]),此时就填上了以top为底座的坑,top弹出。
  4. 继续尝试当前遍历的元素能不能压入栈中,重复上述计算,依次计算每一个坑中每一行的雨水量,相当于就是一个填坑的过程。

代码如下

public class Solution {
    public int trap(int[] height) {
        //单调栈
        Deque<Integer> st = new LinkedList<>();
        st.push(0);
        int sum = 0;
        //依次遍历每一列
        for (int i = 1; i < height.length; i++) {
        	//情况1
            if (height[st.peek()] > height[i]) {
                st.push(i);
            } 
            //情况2
            else if (height[st.peek()] == height[i]) {
                st.pop();
                st.push(i);
            } 
            //情况3
            else {
                while (height[st.peek()] < height[i]) {
                    Integer pop = st.pop();
                    if (st.isEmpty()) break;
                    int h = Math.min(height[st.peek()], height[i]) - height[pop];
                    int l = i - st.peek() - 1;
                    sum = sum + h * l;
                }
                st.push(i);
            }
        }
        return sum;
    }
}
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-07-05 23:40:24  更:2022-07-05 23:41:47 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 23:21:55-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码