42.接雨水

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;
}
发布了28 篇原创文章 · 获赞 12 · 访问量 1257

猜你喜欢

转载自blog.csdn.net/weixin_43264478/article/details/103284143