题目:
给定 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
题解:
方法一:按列来求。
遍历每一列,然后分别求出这一列两边最高的墙。找出较矮的一端,和当前列的高度比较,结果就是上边的三种情况。
package test;
class Solution {
public int trap(int[] height) {
int sum = 0;
//最两端的列不用考虑,因为一定不会有水。所以下标从 1 到 length - 2
for (int i = 1; i < height.length - 1; i++) {
int max_left = 0;
//找出左边最高
for (int j = i - 1; j >= 0; j--) {
if (height[j] > max_left) {
max_left = height[j];
}
}
int max_right = 0;
//找出右边最高
for (int j = i + 1; j < height.length; j++) {
if (height[j] > max_right) {
max_right = height[j];
}
}
//找出两端较小的
int min = Math.min(max_left, max_right);
//只有较小的一段大于当前列的高度才会有水,其他情况不会有水
if (min > height[i]) {
sum = sum + (min - height[i]);
}
}
return sum;
}
}
public class Main{
public static void main (String []args){
int[] a = {0,1,0,2,1,0,1,3,2,1,2,1};//升序
Solution p = new Solution();
int b = p.trap(a);
System.out.println("结果:"+ b);
}
}
方法二:先把第i个的左右两边最大的高度放到一个数组里,用的时候直接取出来。复杂度是O(n),面试的时候写这个。
package test;
class Solution {
public int trap(int[] height) {
int sum = 0;
int[] max_left = new int[height.length];
int[] max_right = new int[height.length];
// 找到左边的最大值数组(第二个数到倒数第二个数)
for (int i = 1; i < height.length - 1; i++) {
max_left[i] = Math.max(max_left[i - 1], height[i - 1]);
}
// 找到右边的最大值数组(倒数第二个数到第二个数)
for (int i = height.length - 2; i > 0; i--) {//j和i再一次没看出来...length-2是倒数第二个
max_right[i] = Math.max(max_right[i + 1], height[i + 1]);
}
// 找到第i个数两边比较小的数,然后判断是不是比i小,如果小的话,就把长度加上
for (int i = 1; i < height.length - 1; i++) {
int min = Math.min(max_left[i], max_right[i]);
if(min > height[i]){//最小值大于height[i]
sum = sum + (min - height[i]);
}
}
return sum;
}
}
public class Main{
public static void main (String []args){
int[] a = {0,1,0,2,1,0,1,3,2,1,2,1};//升序
Solution p = new Solution();
int b = p.trap(a);
System.out.println("结果:"+ b);
}
}
方法三:左右指针(不太好理解)
package test;
//只要保证 height [ left - 1 ] < height [ right + 1 ] ,那么 max_left 就一定小于 max_right。
//因为 max_left 是由 height [ left - 1] 更新过来的,而 height [ left - 1 ] 是小于 height [ right + 1] 的,
//而 height [ right + 1 ] 会更新 max_right,所以间接的得出 max_left 一定小于 max_right。
//反之,我们就从右到左更。
class Solution {
public int trap(int[] height) {
int sum = 0;
int max_left = 0;
int max_right = 0;
int left = 1;
int right = height.length - 2; // 加右指针进去
for (int i = 1; i < height.length - 1; i++) {// {0,1,0,2,1,0,1,3,2,1,2,1}
//从左到右更
if (height[left - 1] < height[right + 1]) {
max_left = Math.max(max_left, height[left - 1]);
int min = max_left;
if (min > height[left]) {
sum = sum + (min - height[left]);
}
left++;
//从右到左更
} else {
max_right = Math.max(max_right, height[right + 1]);//max(0, 1)
int min = max_right;//min = 1
if (min > height[right]) {
sum = sum + (min - height[right]);
}
right--;
}
}
return sum;
}
}
public class Main{
public static void main (String []args){
int[] a = {0,1,0,2,1,0,1,3,2,1,2,1};//升序
Solution p = new Solution();
int b = p.trap(a);
System.out.println("结果:"+ b);
}
}