Problem: https://leetcode.com/problems/trapping-rain-water/
Solution1:
找出当前列的左边最高列和右边最高列,取较小的列与当前列进行比较,若当前列矮于较小列,则结果累加
class Solution {
public int trap(int[] height) {
int ans = 0;
for(int i = 1; i < height.length -1; i++) {
int max_left = 0, max_right = 0;
for(int j = i-1; j>= 0; j--) {
if(height[j] > max_left) {
max_left = height[j];
}
}
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);
ans += Math.max(0, min - height[i]);
}
return ans;
}
}
时间复杂度为O(n2)
参考链接:https://leetcode-cn.com/problems/trapping-rain-water/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-w-8/
Solution2:
动态规划算法,存储从第 1 位到第 n-1 位的左右最大值
class Solution {
public int trap(int[] height) {
// dynamic programming
int[] left = new int[height.length];
int[] right = new int[height.length];
for(int i = 1; i < height.length -1; i++) {
left[i] = Math.max(left[i-1], height[i-1]);
}
for(int i = height.length - 2; i > 0; i--) {
right[i] = Math.max(right[i+1], height[i+1]);
}
int ans = 0;
for(int i = 1; i < height.length - 1; i++) {
ans += Math.max(0, Math.min(left[i], right[i]) - height[i]);
}
return ans;
}
}
时间复杂度降为O(n)
Solution3:
双指针法
设定 0 位和 n-1 位分别为两个指针,将两个指针的height进行比较,迭代较小的那一个
这个方法的好处是,可以不断改变迭代的方向(左→右或者右←左),而or循环只能进行一个方向的迭代
class Solution {
public int trap(int[] height) {
// two pointers
int left = 0;
int right = height.length -1;
int max_left = 0;
int max_right = 0;
int ans = 0;
while(left < right) {
if(height[left] < height[right]) {
if(height[left] >= max_left) {
max_left = height[left];
} else {
ans += max_left - height[left];
}
left++;
} else {
if(height[right] >= max_right) {
max_right = height[right];
} else {
ans += max_right - height[right];
}
right--;
}
}
return ans;
}
}
Solution4:
采用压栈思想
若current的高度大于栈顶高度,则弹出栈顶(第 i 位),并计算第 i 位的储水量
储水量的计算方法为距离 x 高度,距离 = current - 当前栈顶 - 1,高度 = min(当前栈顶位的高度,current位的高度)
class Solution {
public int trap(int[] height) {
// 利用压栈思想
int sum = 0;
Stack<Integer> stack = new Stack<>();
int current = 0;
while (current < height.length) {
while(!stack.empty() && height[current] > height[stack.peek()]) {
int h = height[stack.peek()];
stack.pop();
if(stack.empty()) {
break;
}
int dis = current - stack.peek() - 1;
int min = Math.min(height[current], height[stack.peek()]);
sum += dis * (min - h);
}
stack.push(current);
current++;
}
return sum;
}
}
该方法初步理顺,还要加深理解