【LeetCode】42.接雨水
作者:互联网
题目链接
42. 接雨水
题目描述
解题思路
暴力法(按列求取雨水值)
因为首尾元素不可能存在雨水,所以可以不用考虑首尾元素。
对于剩余的每个元素,分别计算从该元素开始,从左和从右开始开始的最大值,然后当前元素对应的能够接的雨水值 = Math.min(maxLeft,maxRight) - height[i];
时间复杂度:O(n2)
空间复杂度:O(1)
动态规划
在暴力法中,我们每次都要计算当前坐标对应的左边最大值maxLeft以及右边最大值maxRight,所以直接导致时间复杂度为O(n2),然而这些值都是固定的,所以我们可以提前利用两个数组maxleft[]以及maxRight[]记录每个下标对应的左边最大值和右边最大值。
时间复杂度:O(n)
空间复杂度:O(n)
单调栈
单调递减栈,栈中存放的是索引值,因为通过索引值也可以得到height数组中的元素值。
如果当前索引对应的height数组值 <= 前一个索引对应的height数组值,那么接不雨水。
如果当前索引对应的height数组值 > 前一个索引对应的height数组值,那么才有可能接到雨水(注意是有可能,而不是一定,只有同时满足单调栈不为空的时候才能接到雨水)
参考下图就一目了然,利用单调栈也可以理解为是按行计算雨水值
如果当前下标对应的height数组值小于栈顶元素则入栈。
如果当前下标对应的height数组值大于栈顶元素且当前stack不为空,则说明此时这种情况存在雨水值,雨水值的计算方式如下:
- 首先记录value = 弹栈元素对应的height数组值
- 其次记录Math.min(新的栈顶元素对应的height数组值,以及当前索引对应的height数组值),然后减去value值,则为水坑对应的高度。
- 水坑的宽度 = 当前索引 - 新的栈顶元素。
AC代码
暴力法
class Solution {
//按照每列的雨水数目计算结果
public int trap(int[] height) {
int ans = 0;
//因为开头结尾不会有雨水,所以可以不用考虑
for(int i = 1; i < height.length - 1; i++){
int maxLeft = height[i];
int maxRight = height[i];
for(int j = i - 1; j >= 0; j--){
if(height[j] > maxLeft){
maxLeft = height[j];
}
}
for(int j = i + 1; j < height.length; j++){
if(height[j] > maxRight){
maxRight = height[j];
}
}
ans += Math.min(maxLeft,maxRight) - height[i];
}
return ans;
}
}
动态规划
class Solution {
public int trap(int[] height) {
if(height.length == 0) return 0;
int maxLeft[] = new int[height.length];
int maxRight[] = new int[height.length];
int ans = 0;
maxLeft[0] = 0;
for(int i = 1; i < height.length; i++){
maxLeft[i] = Math.max(height[i - 1],maxLeft[i-1]);
}
maxRight[height.length-1] = 0;
for(int i = height.length - 2; i >= 0; i--){
maxRight[i] = Math.max(height[i+1],maxRight[i+1]);
}
for(int i = 1; i < height.length; i++){
int h = Math.min(maxLeft[i],maxRight[i]);
if(h > height[i]){
ans += h - height[i];
}
}
return ans;
}
}
//改进版动态规划
class Solution {
public int trap(int[] height) {
if(height.length == 0) return 0;
int maxRight[] = new int[height.length];
int ans = 0;
int maxLeft = 0;
maxRight[height.length-1] = 0;
for(int i = height.length - 2; i >= 0; i--){
maxRight[i] = Math.max(height[i+1], maxRight[i+1]);
}
for(int i = 1; i < height.length; i++){
maxLeft = Math.max(maxLeft,height[i - 1]);
int h = Math.min(maxLeft,maxRight[i]);
if(h > height[i]){
ans += h - height[i];
}
}
return ans;
}
}
//改进版,双指针法
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++) {
//从左到右更
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]);
int min = max_right;
if (min > height[right]) {
sum = sum + (min - height[right]);
}
right--;
}
}
return sum;
}
作者:windliang
链接:https://leetcode-cn.com/problems/trapping-rain-water/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-w-8/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
单调栈
class Solution {
public int trap(int[] height) {
Stack<Integer> st = new Stack<>();
int ans = 0;
for(int i = 0; i < height.length; i++){
while(!st.isEmpty() && height[i] > height[st.peek()]){
int index = st.pop();
int value = height[index];
if(st.isEmpty() == false) ans += (Math.min(height[st.peek()],height[i]) - value) * (i-st.peek()-1);
}
st.push(i);
}
return ans;
}
}
标签:maxRight,int,max,42,雨水,height,length,maxLeft,LeetCode 来源: https://www.cnblogs.com/XDU-Lakers/p/14194856.html