接雨水

157 阅读1分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第12天,点击查看活动详情

前言

笔者除了大学时期选修过《算法设计与分析》和《数据结构》还是浑浑噩噩度过的(当时觉得和编程没多大关系),其他时间对算法接触也比较少,但是随着开发时间变长对一些底层代码/处理机制有所接触越发觉得算法的重要性,所以决定开始系统的学习(主要是刷力扣上的题目)和整理,也希望还没开始学习的人尽早开始。

系列文章收录《算法》专栏中。

力扣题目链接

问题描述

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

示例 1:

image.png

输入: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 * 10^4
  • 0 <= height[i] <= 10^5

剖析

暴力破解

这道题笔者的第一反应就是暴力破解,两层for循环拿到每一个位置的储水量,左边的每次在往右边移动的时候柱子只会变高不会变矮,右边柱子会逐渐变少所以是动态的需要在第二层循环中重新计算右边柱子的最大值,注意还需要减去每个位置柱子本身的值。

public static int trap(int[] height) {
    int result = 0;

    //一直再往右边移动所以左边最大值不用归0
    int leftMax = 0;
    for (int i = 0; i < height.length; i++) {
        leftMax = Math.max(height[i], leftMax);
        //右边的一直再变少所以需要归0
        int rightMax = 0;
        for (int j = i; j < height.length; j++) {
            rightMax = Math.max(height[j], rightMax);
        }
        //一直累加,加上最小的并减去本身
        result = result + Math.min(leftMax, rightMax) - height[i];
    }
    return result;
}

复杂度:

  • 时间复杂度:O(n^2)。
  • 空间复杂度:O(1)

动态规划

笔者没看出来是用了动态规划,看了下视频的描述写出来的,使用两个数组存储往左和往右的最大值,利用两次for循环去进行存储,再利用一次for循环去累加每个位置的积水,积水的算法和暴力破解一样。

public static int trapUseDp(int[] height) {
    int result = 0;

    //从左往右存放每个下标往左最大的值
    int[] leftMaxArry = new int[height.length];
    int leftMax = 0;
    for (int i = 0; i < height.length; i++) {
        leftMax = Math.max(leftMax, height[i]);
        leftMaxArry[i] = leftMax;
    }

    //从右往左存放每个下标往右最大的值
    int[] rightMaxArry = new int[height.length];
    int rightMax = 0;
    for (int j = (height.length - 1); j >= 0; j--) {
        rightMax = Math.max(rightMax, height[j]);
        rightMaxArry[j] = rightMax;
    }

    //叠加雨水,每个凹槽的值等于对应下标Math.min(leftMaxArry[i], rightMaxArry[i]) - height[i]
    for (int i = 0; i < height.length; i++) {
        result = result + Math.min(leftMaxArry[i], rightMaxArry[i]) - height[i];
    }
    return result;
}