Description:
Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining.
For example,
Given [0,1,0,2,1,0,1,3,2,1,2,1], return 6.
问题描述:
给定一个数组,数组元素为宽为1的柱的长,求出这个平面中的这个图形在下雨后能装的水的面积
例子:
输入 [0,1,0,2,1,0,1,3,2,1,2,1],返回6.
实际上,这题是Trapping Rain WaterII的前置题,不过因为我做的顺序是颠倒的,于是可以借用下II的思路。
解法1(最直观的套用II):
/*
可以看到,套路几乎没变,只是由立体变为了平面,可以选择的方向也只有两个,左和右(其实对于特定一个柱,只能往左或者右一个方向)
我们注意到,实际上从边缘的两个柱子开始,决定迭代顺序的决定性条件是两者的长,谁更长谁就先。
因此这也为我们解法2的优化提供了思路
*/
class Solution {
private class Cell implements Comparable<Cell>{
int index;
int height;
public Cell(int index, int height){
this.index = index;
this.height = height;
}
@Override
public int compareTo(Cell cell1){
return height - cell1.height;
}
}
public int trap(int[] height) {
if(height == null || height.length < 2) return 0;
int len = height.length;
Queue<Cell> queue = new PriorityQueue<Cell>();
boolean[] visited = new boolean[len];
queue.offer(new Cell(0, height[0]));
queue.offer(new Cell(len - 1, height[len - 1]));
visited[0] = true;
visited[len - 1] = true;
int res = 0;
while(!queue.isEmpty()){
Cell cell = queue.poll();
int i = cell.index + 1;
if(i < len && !visited[i]){
visited[i] = true;
res += Math.max(0, cell.height - height[i]);
queue.offer(new Cell(i, Math.max(height[i], cell.height)));
}
int j = cell.index - 1;
if(j >= 0 && !visited[j]){
visited[j] = true;
res += Math.max(0, cell.height - height[j]);
queue.offer(new Cell(j, Math.max(height[j], cell.height)));
}
}
return res;
}
}
解法2(two pointers):
/*
我为了追求与II的连贯,也为了更加清晰直观,因此保留了Cell。
注意到,这个解法已经没有优先级队列了。
*/
class Solution {
private class Cell implements Comparable<Cell>{
int index;
int height;
public Cell(int index, int height){
this.index = index;
this.height = height;
}
@Override
public int compareTo(Cell cell1){
return height - cell1.height;
}
}
public int trap(int[] height) {
if(height == null || height.length < 2) return 0;
int len = height.length;
Cell left = new Cell(0, height[0]), right = new Cell(len - 1, height[len - 1]);
int res = 0;
while(left.index < right.index){
//注意这里,长度决定了处理的先后顺序,内部的运算与II别无二致
if(left.height < right.height){
int i = left.index + 1;
res += Math.max(0, left.height - height[i]);
left.index = i;
left.height = Math.max(left.height, height[i]);
}else{
int i = right.index - 1;
res += Math.max(0, right.height - height[i]);
right.index = i;
right.height = Math.max(right.height, height[i]);
}
}
return res;
}
}