面试经典150题——接雨水

面试经典150题 day16

      • 题目来源
      • 我的题解
        • [方法一 暴力解法](#方法一 暴力解法)
        • [方法二 备忘录优化](#方法二 备忘录优化)
        • [方法三 双指针](#方法三 双指针)
        • [方法四 单调栈](#方法四 单调栈)

题目来源

力扣每日一题;题序:42

我的题解

方法一 暴力解法

计算每一个位置的水有多少。找到每个位置的左侧最大值和右侧最大值,然后取两者中的较小的(水桶装水原理),如果较小的大于当前位置,则表示该位置可以接雨水,接雨水的量:min(leftMax,rightMax)-cur

以前是能过的,现在好像过不了了
时间复杂度 :O( n 2 n^2 n2)
空间复杂度:O(1)

java 复制代码
class Solution {
    public  int trap(int[] height) {
        int res=0;
        for(int i=1;i<height.length-1;i++){
        	//左侧最大值的位置
	        int left=findMax(height,0,i);
	        //右侧最大值的位置
	        int right=findMax(height,i,height.length);
	        //两者中的较小值
	        int min=Math.min(height[left],height[right]);
	        if(min>=height[i])
	            res+=min-height[i];
        }
        return res;
    }
	//找最大值所在位置
    private  int findMax(int[] height, int s, int e) {
        int max=height[s];
        int index=s;
        for(int i=s;i<e;i++){
	        if (height[i] > max) {
	            max=height[i];
	            index = i;
	        }
        }
        return index;
    }
}
方法二 备忘录优化

在方法一中求左侧和右侧的最大值都会重复计算,因此可以提前预先计算每个位置的左侧和右侧最大值
时间复杂度:O(n)

空间复杂度:O(n)

java 复制代码
public  int trap(int[] height) {
    int res=0;
    int n=height.length;
    int[] left=new int[n];
    int[] right=new int[n];
    left[0]=height[0];
    right[n-1]=height[n-1];
    for(int i=1;i<n;i++)
        left[i]=Math.max(left[i-1],height[i]);
    for(int i=n-2;i>=0;i--)
        right[i]=Math.max(right[i+1],height[i]);
    for(int i=1;i<height.length-1;i++){
        int min=Math.min(left[i],right[i]);
        res+=min-height[i];
    }
    return res;
}
方法三 双指针

两个指针分别指向还未被遍历的最左侧和最右侧,然后依次遍历每个位置,leftMax和rightMax不再是当前位置左侧和右侧的最大值,而是0,left和right,end中的最大值。
时间复杂度:O(n)

空间复杂度:O(1)

java 复制代码
class Solution {
  public static int trap(int[] height) {
    int res=0;
    int left=0,right=height.length-1;
    int leftMax=height[left],rightMax=height[right];
    while(left<right){
      if(height[left]<height[right]){
        //找左边最大
        if(height[left]>leftMax)
          leftMax=height[left];
        else
          res+=leftMax-height[left];
        left++;
      }else{
        //找右边最大
        if(height[right]>rightMax)
          rightMax=height[right];
        else
          res+=rightMax-height[right];
        right--;
      }
    }
    return res;
  }
}
方法四 单调栈

该方法计算雨水量是横向计算每个水平面可以接的雨水量。

用单调栈计算能接的雨水总量。维护一个单调栈,单调栈存储的是下标,满足从栈底到栈顶的下标对应的数组 height 中的元素递减。

从左到右遍历数组,遍历到下标 iii 时,如果栈内至少有两个元素,记栈顶元素为 top,top 的下面一个元素是 left,则一定有 heightleft≥heighttop。如果 heighti>heighttop,则得到一个可以接雨水的区域,该区域的宽度是 i−left−1,高度是 min⁡(heightleft,heighti)−heighttop,根据宽度和高度即可计算得到该区域能接的雨水量。

为了得到 left,需要将 top 出栈。在对 top 计算能接的雨水量之后,left 变成新的 top,重复上述操作,直到栈变为空,或者栈顶下标对应的 height中的元素大于或等于 heighti。

在对下标 i 处计算能接的雨水量之后,将 i 入栈,继续遍历后面的下标,计算能接的雨水量。遍历结束之后即可得到能接的雨水总量。
时间复杂度:O(n)

空间复杂度:O(n)

java 复制代码
class Solution {
  public static int trap(int[] height) {
    int res=0;
    Stack<Integer> stack=new Stack<>();
    int i=0;
    while(i<height.length){
      while(!stack.isEmpty()&&height[stack.peek()]<height[i]){
        int low=stack.pop();
        if(stack.isEmpty())
          break;
        int min=Math.min(height[stack.peek()],height[i]);
        int width=i-stack.peek()-1;
        res+=width*(min-height[low]);
      }
      stack.push(i++);
    }
    return res;
  }
}

有任何问题,欢迎评论区交流,欢迎评论区提供其它解题思路(代码),也可以点个赞支持一下作者哈😄~

相关推荐
代码山河1 小时前
基本类型转换:自动类型转换与强制类型转换
java·学习·架构·教程·面向对象·项目
Escalating_xu2 小时前
【Linux 网络编程】五种 I/O 模型与非阻塞 I/O:从“等数据”到正确处理 EAGAIN
java·linux·网络
程序猿乐锅3 小时前
万字详解Single-flight(单飞模式)
java·开发语言·分布式·后端·学习·single-flight
AiNightVision3 小时前
无人机夜视模块如何选择?——从参数指标到系统集成的完整选型指南
人工智能·算法·计算机视觉·车载系统·无人机·视频·智能硬件
Java后端的Ai之路3 小时前
【AIAgent开发】-Agent工具封装成CLI(纯干货!!!)
java·javascript·人工智能·agent·cli
AntsData3 小时前
用 12K+ 条亚马逊评论信号,定位机械键盘下一版该改什么
java·大数据·计算机外设
code2cat3 小时前
【随笔】连续批处理:长短请求怎样在迭代之间补位
java·人工智能·后端·大语言模型·vllm
最强小杰3 小时前
DeepSeek V4 Flash + Codex CLI 接入教程:原生 Responses API 适配,从配置到跑通收藏这篇就够了(2026)
java·前端·python·ai
考研保研资料分享3 小时前
2022环境工程保研北师大:三校专业追问、论文贡献与择校复盘
面试
牧羊人.3334 小时前
卷积神经网络之VGG
人工智能·深度学习·神经网络·算法·cnn