题目描述
-
给定
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
提示:
n == height.length
1 <= n <= 2 * 104
0 <= height[i] <= 105
解法
思路:
雨水容量由左右两侧较矮的边界决定。我们使用两个指针从数组两端向中间移动,同时跟踪左右两边的最大高度。
左指针的高度小于右指针时,水高度由左指针决定,左侧每个位置计算水的容量,每个位置水的容量是左侧最大的高度与当前位置的高度差。
步骤:
- 初始化左右指针分别指向数组的首尾
- 初始化左右最大高度为0
- 当左指针小于右指针时循环:
- 如果左指针高度小于右指针高度:
- 如果左指针高度大于等于左最大高度,更新左最大高度
- 否则,计算当前位置能存储的雨水量并累加
- 左指针右移
- 否则:
- 如果右指针高度大于等于右最大高度,更新右最大高度
- 否则,计算当前位置能存储的雨水量并累加
- 右指针左移
- 如果左指针高度小于右指针高度:
代码:
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;public class leetcode_007{public static int trap(int[] height) {if (height == null || height.length == 0) return 0;int left = 0, right = height.length - 1;int leftMax = 0, 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;}public static void main(String[] args) {Scanner sc = new Scanner(System.in);String[] line = sc.nextLine().split(",");int[] nums= Arrays.stream(line).mapToInt(Integer::parseInt).toArray();int result =trap(nums);System.out.println(result);}
}
想法
思路:
按行计算每行的水的容量。第一行找到两侧端点,端点之间小于1的地方可以容纳水。第二行找到两侧端点,端点之间高度小于2的地方可以容纳水,依次类推。该算法的时间复杂度为O(maxHeight*n),该算法在大数据的情况下运行时间超出。
代码:
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;public class leetcode_007{public static int trap(int[] height) {if (height == null || height.length == 0) return 0;int maxHeight = Arrays.stream(height).max().getAsInt();int waterSum = 0;// 预处理:找到每层的第一个和最后一个非零位置for (int i = 1; i <= maxHeight; i++) {int left = -1, right = -1;// 找到当前层的左右边界for (int j = 0; j < height.length; j++) {if (height[j] >= i) {left = j;break;}}for (int j = height.length - 1; j >= 0; j--) {if (height[j] >= i) {right = j;break;}}// 计算当前层的雨水if (left != -1 && right != -1 && left < right) {for (int j = left + 1; j < right; j++) {if (height[j] < i) {waterSum++;}}}}return waterSum;}public static void main(String[] args) {Scanner sc = new Scanner(System.in);String[] line = sc.nextLine().split(",");int[] nums= Arrays.stream(line).mapToInt(Integer::parseInt).toArray();int result =trap(nums);System.out.println(result);}
}