1. 单个存储栈
* 其实某一格能容纳的水量one就是:
* one= max(left)-max(right)- arr[i]
* 如果小于等于0 ==0
* 如果大于0才有值
* 问题就到了找到每一个arr[i]左右两边的最大值
* 最直观想到的就是用两个栈,分别存截止到当前元素arr[i]的左右两边的最大值
* stack<Integer> leftMax 代表左边的,从0到arr[i]遍历,只有在当前值大于栈中的值时才入栈,但是
* 仔细想了一下,好像没有必要用到栈,因为不涉及弹出,最后用一个变量 maxLeft代表吧
* stack<Integer> rightMax 代表右边的 ,顺序先从左到右,我们发现如果第一个值如果最大,
* 后面的就不入栈了,所以左----》右的顺序不行
* 如果是从最右边到arr[i+1]是可以了,而且是可以弹出的,所以我们右边用栈来表示
package com.pf.org.cms.yushui;
import java.util.Stack;
public class DongTai {
public static int trap(int[] height) {
/**
* 因为想存水至少需要3个
*/
if (height.length <= 2) {
return 0;
}
/***
* 总存水量
*/
int maxShui = 0;
/***
* 单个格子的存水量
*/
int oneShui = 0;
/***
* maxLeft要存的是从第1个arr[0]到倒数第二个arr[i-1]之间的最大值
*/
int maxLeft = 0;
/***
* rightStack 要存的是从第3个arr[2]到最后一个arr[len-1]之间所有的最大值
*/
Stack<Integer> rightStack = new Stack<>();
/**
* 先放入最后一个
*/
rightStack.push(height[height.length - 1]);
/**
* 从倒数第二个开始,到正数第三个也就是arr[2]结束
*/
for (int i = height.length - 2; i > 1; i--) {
if (height[i] > rightStack.peek()) {
rightStack.push(height[i]);
} else {
rightStack.push(rightStack.peek());
}
}
/***
* 因为第一个格子和最后一个格子是存不了水的
*/
for (int i = 1; i < height.length - 1; i++) {
if (height[i - 1] > maxLeft) {
maxLeft = height[i - 1];
}
oneShui = Math.min(maxLeft, rightStack.pop()) - height[i];
if (oneShui < 0) {
oneShui = 0;
}
System.out.println(i + " " + oneShui);
maxShui += oneShui;
}
return maxShui;
}
public static void main(String[] args) {
int arr[] = new int[]{0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1};
System.out.println(trap(arr));
}
}
输出结果:
1 0
2 1
3 0
4 1
5 2
6 1
7 0
8 0
9 1
10 0
6
力扣分析:
执行用时 :13 ms, 在所有Java提交中击败了40.74%的用户
内存消耗 :36.2 MB, 在所有Java提交中击败了92.01%的用户
2. 简化单存储栈,但是需要额外添加一个栈
在上面的栈存储上面,存的是1 222 333 333
其实数量如果大的话,其中的2和3如果能存一个就好了
变成1 2 3
但是再利用一个栈存入栈的下标,比如上述的 11 10 7
2.1 这就是典型的以空间换取时间的算法:
/***
* rightStack 要存的是从第3个arr[2]到最后一个arr[len-1]之间所有的最大值
* 最后变为 1 2 3
*/
Stack<Integer> rightStack = new Stack<>();
/***
* rightSign存的是每一个入栈的下标
* 最后变为 11 10 7
*/
Stack<Integer> rightSign = new Stack<>();
核心代码变化:
入栈代码变化:
for (int i = height.length - 2; i > 1; i--) {
if (height[i] > rightStack.peek()) {
rightStack.push(height[i]);
} else {
rightStack.push(rightStack.peek());
}
}
for (int i = height.length - 2; i > 1; i--) {
if (height[i] > rightStack.peek()) {
rightStack.push(height[i]);
}
}
package com.pf.org.cms.yushui;
import java.util.LinkedList;
import java.util.Stack;
public class DongTai {
public static int trap(int[] height) {
/**
* 因为想存水至少需要3个
*/
if (height.length <= 2) {
return 0;
}
/***
* 总存水量
*/
int maxShui = 0;
/***
* 单个格子的存水量
*/
int oneShui = 0;
/***
* maxLeft要存的是从第1个arr[0]到倒数第二个arr[i-1]之间的最大值
*/
int maxLeft = 0;
/***
* rightStack 要存的是从第3个arr[2]到最后一个arr[len-1]之间所有的最大值
*/
Stack<Integer> rightStack = new Stack<>();
/***
* rightSign存的是每一个入栈的下标
*/
Stack<Integer> rightSign = new Stack<>();
/**
* 先放入最后一个
*/
rightStack.push(height[height.length - 1]);
rightSign.push(height.length - 1);
/**
* 从倒数第二个开始,到正数第三个也就是arr[2]结束
*/
for (int i = height.length - 2; i > 1; i--) {
if (height[i] > rightStack.peek()) {
rightStack.push(height[i]);
rightSign.push(i);
}
}
/***
* 最后的一个入栈标志,先谈出
*/
int rightPop = rightStack.pop();
/***
* 因为第一个格子和最后一个格子是存不了水的
*/
for (int i = 1; i < height.length - 1; i++) {
if (height[i - 1] > maxLeft) {
maxLeft = height[i - 1];
}
System.out.println(i + "--------" + rightSign.peek());
if (i == rightSign.peek()) {
rightSign.pop();
rightPop = rightStack.pop();
}
oneShui = Math.min(maxLeft, rightPop) - height[i];
if (oneShui < 0) {
oneShui = 0;
}
System.out.println(i + " " + oneShui);
maxShui += oneShui;
}
return maxShui;
}
public static void main(String[] args) {
int arr[] = new int[]{0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1};
System.out.println(trap(arr));
}
}
结果分析:
1--------7
1 0
2--------7
2 1
3--------7
3 0
4--------7
4 1
5--------7
5 2
6--------7
6 1
7--------7
7 0
8--------10
8 0
9--------10
9 1
10--------10
10 0
最后结果是:6
力扣统计:
执行用时 :5 ms, 在所有Java提交中击败了48.83%的用户
内存消耗 :36.2 MB, 在所有Java提交中击败了92.01%的用户