1.暴力法
对height[]遍历下标为[1,height.length-1] 的可能存水位置,
存水位置的两侧一定存在更大height[]值
存水量 由每侧的height[]最大值 中的 较小者 决定
class Solution {
public int trap(int[] height) {
int ans=0;
int size = height.length;
int max_left=0,max_right=0;
for(int i=1;i<size-1;i++){
for(int j=i;j>0;j--){
max_left=Math.max(max_left,height[j]);
}
for(int j=i;j<size;j++){
max_right=Math.max(max_right,height[j]);
}
ans+=Math.min(max_left,max_right);
}
return ans;
}
}
2.动态规划:将多阶段问题转化成一系列单阶段问题 ,利用各阶段的关系,逐个求解
将方法一所需要的两侧墙的高度保存在数组中,只需要O(n)的时间复杂度
class Solution {
public int trap(int[] height) {
int ans=0;
//开辟存储墙高的数组
int max_left[]=new int[height.length];//为了for循环内直接用i,多开辟了两个空间存储空间
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]);////max_left[]默认为0
}
//遍历得到每个位置右侧最高值
for(int i=height.length-2;i>0;i--){
max_right[i]=Math.max(max_right[i+1],height[i+1]);
}
//找到决定水位的墙
for(int j=1;j<height.length-1;j++){
int min=Math.min(max_left[j],max_right[j]);//得到下标为j的元素两侧较小
if(min>height[j])
ans+=min-height[j];
}
return ans;
}
}
想去掉最后一个for循环内的if,做了一点修改 让max_[i]保存包括height[i]在内的某侧最大值,提交时在第八行执行出错,还没修改好 烦请各位大佬看一哈
class Solution {
public int trap(int[] height) {
int ans=0;
//开辟存储墙高的数组
int max_left[]=new int[height.length];
max_left[0]=height[0];
int max_right[]=new int[height.length];
max_right[height.length-1]=height[height.length-1];
//遍历得到每个位置左侧最高值
for(int i=1;i<height.length-1;i++){
max_left[i]=Math.max(max_left[i-1],height[i]);//存储前i+1个值的最大值,可能恰好保存了height[i]
}
//遍历得到每个位置右侧最高值
for(int i=height.length-2;i>0;i--){
max_right[i]=Math.max(max_right[i+1],height[i]);
}
//找到决定水位的墙
for(int j=1;j<height.length-1;j++){
int min=Math.min(max_left[j],max_right[j]);//得到下标为j的元素两侧较小
ans+=min-height[j];
}
return ans;
}
}
3.双指针,左右指针
class Solution {
public int trap(int[] height) {
int left=0,right =height.length-1;
int ans=0;
int left_max=0,right_max=0;
while(left<right){//执行循环到双指针重合
if(height[left]<height[right]){//在height[left]右侧有更高的墙,此时在height[left]可能有存水,水量由height[left]左侧最高的墙决定
if(height[left]>=left_max)
left_max=height[left];//没有存水,更新最大值
else
ans+=(left_max-height[left]);//
++left;//指针移动,未探测存水范围减小
}else{
if(height[right]>=right_max)
right_max=height[right];
else
ans+=(right_max-height[right]);
--right;
}
}
return ans;
}
}
遗留问题:把if。else改成三目就会报错
4. 找到最高的柱子,分别处理
5. 栈
这个方法对我现在这个水平是难以想出的,借鉴大佬的方法
提到栈,印象最深的就是括号匹配了 把求两个方块体之间的积水 对应 成两个方块体间的匹配,即两个括号的匹配(比较高的方块体需要匹配多次)
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 distance = current - stack.peek() - 1; //两堵墙之前的距离。
int min = Math.min(height[stack.peek()], height[current]);
sum = sum + distance * (min - h);
}
stack.push(current); //当前指向的墙入栈
current++; //指针后移
}
return sum;
}