接雨水
今天的题目是力扣面试经典算法150题中的困难难度数组题目:分发糖果。
题目链接:https://leetcode.cn/problems/trapping-rain-water/description/?envType=study-plan-v2&envId=top-interview-150
题目描述
给定 n 个非负整数表示每个宽度为 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 个单位的雨水(蓝色部分表示雨水)。
-
题目分析
题目内容不多,主要还是看示例中的图片来进行分析。
首先题目会给定一个非负整数数组,数组的每个元素对应到坐标上的一个柱状图。如上图。
题目的要求是,我们需要计算出这个数组中可以容下多少单位的水。 注意Y坐标轴不参于接水。
对于题目的要求,比较考验空间想象能力以及空间计算能力。
解题思路
困难题目名不虚传啊,昨天的开胃菜一对比确实不难。
这个题目要解答主要有两个点需要确定。
- 我们首先要界定两个位置,确保这个两个位置可以接住水,比如示例中下标1到下标3中间可以接水,下标3到下标7又开始接水,下标8到下标10又可以接水。
- 确定边界位置以后,我们要计算能装多少水。注意,这里我们确定能装的水的数量,不能等确定两个边界后再算,这样比较难算,我们应该在每次向下获取下标值判定是否到边界时就应该把移动这个下标所能装的水的数量计算好。
思考到这里,其实方法已经出现了。没错,就是双指针法。
双指针法也是老演员了,数组题目可以说出现很多次了。
那么本题使用双指针法解答如下:
- 初始化指针:
left 和 right 分别指向数组的起始位置和末尾位置。
leftMax 和 rightMax 分别记录左侧和右侧的最大高度。
water 用于累计总的雨水量。 - 移动指针:
如果 height[left] < height[right],则移动左指针。
否则,移动右指针。 - 更新最大高度:
如果当前高度大于等于已知的最大高度,则更新最大高度。
否则,当前位置可以接住的雨水量为最大高度减去当前位置的高度。 - 累计雨水量:
将每次计算的雨水量累加到 water 中。
实际算法代码
以下是双指针法的代码实现:
public class Solution {public static void main(String[] args) {Solution solution = new Solution();int[] height = {0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1};System.out.println(solution.trap(height)); // 输出 6}public int trap(int[] height) {if (height == null || height.length <= 2) {return 0;}int left = 0;int right = height.length - 1;int leftMax = 0;int rightMax = 0;int water = 0;while (left < right) {if (height[left] < height[right]) {// 如果左指针的高度小于右指针的高度if (height[left] >= leftMax) {// 更新左侧最大高度leftMax = height[left];} else {// 左侧当前位置可以接住的雨水量water += leftMax - height[left];}left++; // 移动左指针} else {// 如果右指针的高度小于等于左指针的高度if (height[right] >= rightMax) {// 更新右侧最大高度rightMax = height[right];} else {// 右侧当前位置可以接住的雨水量water += rightMax - height[right];}right--; // 移动右指针}}return water;}
}
结果
运行代码,输出结果符合预期:
提交到力扣,也通过测试:
总结
双指针法,用多很多次了,这里不再多废话讲。后面写一篇数组刷题总结。
还剩一题,加油!!!