42. 接雨水-字节跳动高频题

Posted hequnwang10

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了42. 接雨水-字节跳动高频题相关的知识,希望对你有一定的参考价值。

一、题目描述

给定 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

二、解题

动态规划

对于下标i,下雨后能积水的话,取左右两端的最小值,并且当前值小于左右两边值。使用动态规划,分别计算当前值的左右两边的最大值,当前值的积水量等于min(leftMax[i],rightMax[i])−height[i]。

class Solution 
    public int trap(int[] height) 
        //动态规划
        int length = height.length;
        if(length == 0)
            return 0;
        

        int[] leftMax = new int[length];
        leftMax[0] = height[0];
        for(int i = 1;i<length;i++)
            leftMax[i] = Math.max(leftMax[i-1],height[i]);
        
        int[] rightMax = new int[length];
        rightMax[length-1] = height[length-1];
        for(int i = length-2;i>=0;i--)
            rightMax[i] = Math.max(rightMax[i+1],height[i]);
        
        int max = 0;
        for(int i = 0;i<length;i++)
            max += Math.min(leftMax[i],rightMax[i])-height[i];
        
        return max;
    

时间复杂度:O(n);
空间复杂度:O(n);

双指针

维护两个下标指针,左右指针,向中间遍历,保存两个变量,leftMax和rightMax 的值。

class Solution 
    public int trap(int[] height) 
        int ans = 0;
        int left = 0, right = height.length - 1;
        int leftMax = 0, rightMax = 0;
        while (left < right) 
            leftMax = Math.max(leftMax, height[left]);
            rightMax = Math.max(rightMax, height[right]);
            if (height[left] < height[right]) 
                ans += leftMax - height[left];
                ++left;
             else 
                ans += rightMax - height[right];
                --right;
            
        
        return ans;
    

时间复杂度:O(n);
空间复杂度:O(1);

单调栈存储的是下标,满足从栈底到栈顶的下标对应的数组 height 中的元素递减。
如果栈内至少有两个元素,记栈顶元素为 top,top 的下面一个元素是 left,则一定有height[left]≥height[top]。如果 height[i]>height[top],则得到一个可以接雨水的区域,该区域的宽度是 i−left−1,高度是 min(height[left],height[i])−height[top]。

class Solution 
    public int trap(int[] height) 
        //栈
        int ans = 0;
        Deque<Integer> stack = new LinkedList<Integer>();
        int n = height.length;
        for (int i = 0; i < n; ++i) 
            //判断栈是否为空,并且当前值必须大于栈顶值,这样才能形成低洼
            while (!stack.isEmpty() && height[i] > height[stack.peek()]) 
                //低洼处的下标出栈
                int top = stack.pop();
                //栈为空 跳出循环
                if (stack.isEmpty()) 
                    break;
                
                //取左边的高度,当前值为右边的高度
                int left = stack.peek();
                //求面积
                int currWidth = i - left - 1;
                int currHeight = Math.min(height[left], height[i]) - height[top];
                ans += currWidth * currHeight;
            
            //更新右边值
            stack.push(i);
        
        return ans;
    

以上是关于42. 接雨水-字节跳动高频题的主要内容,如果未能解决你的问题,请参考以下文章

字节跳动高频算法题TOP100

字节跳动高频算法题TOP100

C++ 接雨水,不看后悔系列,解一道高频面试题

动态规划字节跳动算法笔试遭遇雨水坑问题

Day8 栈的使用--计算面积 接雨水

Day8 栈的使用--计算面积 接雨水