LeetCode42、雨水をキャッチ

タイトル説明

https://leetcode-cn.com/problems/trapping-rain-water/
ここに画像の説明を挿入

解決

解決策1:AC残業は不可能です(垂直トラバーサル)

下から上に向かって、各レイヤーの累積を計算します。開始と終了が維持されるたびに、レイヤーの数が最大数になります。

class Solution {
    
    
    public int trap(int[] height) {
    
    
        //一层一层的计算
        //维护一个层数,和计算的雨水
        if(height==null ||height.length<3) return 0;

        int res = 0;
        int max = 0;
        for(int i=0;i<height.length;i++){
    
    
            if(max<height[i]){
    
    
                max = height[i];
            }
        }
        for(int i=0;i<=max;i++){
    
    //层数,层数是最大值
            res +=find(height,i);
        }
        return  res;

    }
    /*
    *返回第i层的积水数
    */
    public int find(int[]height,int high){
    
    
        int start=-1,end=-1;
        //必须大于当前的层数的值,这之间的柱子才可能有积水
        for(int i=0;i<height.length;i++){
    
    
            if(height[i]>high){
    
    
                start = i;
                break;
            }
        }
        for(int j=height.length-1;j>0;j--){
    
    
            if(height[j]>high){
    
    //0我就要找比他大的
                end = j;
                break;
            }
        }
        if((start!=-1 && end!=-1) && start<end){
    
    
            //满足条件则有积水
            int res = 0;
            for(int i=start;i<end;i++){
    
    
                if(height[i]<=high){
    
    //小于当前的层数,则
                    res++;
                }
            }
            return res;
        }
        return 0;
    }
}

解決策2:シングルグリッド法(水平トラバーサル)

上記のアルゴリズムは垂直方向の寸法から考えています。次に、水平方向の寸法を見て、各グリッドに格納できる水の高さを計算し、一度に1つのグリッドの水の単位のみを計算する必要があります。

class Solution {
    
    
    public int trap(int[] height) {
    
    
        //一个格子一个格子的计算
        if(height==null ||height.length<3) return 0;

        int res = 0;
        for(int i=1;i<height.length-1;i++){
    
    //从1开始才有积水
            int maxLeft = 0,maxRight = 0;
            for(int j=i-1;j>=0;j--){
    
    
                maxLeft = Math.max(maxLeft,height[j]);
            }
            for(int j=i+1;j<height.length;j++){
    
    
                maxRight = Math.max(maxRight,height[j]);
            }
            int min = Math.min(maxRight,maxLeft);
            if(min - height[i]<=0)//每个格子能积多少水
                continue;//不能积水
            else  res += min-height[i];
        }
        return  res;

    }

}

ここに画像の説明を挿入

時間計算量はO(n * n)に達し、空間計算量はO(1)です。左側と右側を見つけるのに時間がかかることに注意してください。高さをまったく更新する必要がない場合もあるので、次のことができます。これらの値を事前に保存してください

解決策3:動的計画
法rightMax配列を使用してiの最大高さを右に格納し、leftMax配列を使用してiの最大高さを左に格納します。

class Solution {
    
    
    public int trap(int[] height) {
    
    
        //一个格子一个格子的计算其上的积水单位
        if(height==null ||height.length<3) return 0;

        int res = 0;

        int[]leftMax = new int[height.length];
        int[]rightMax = new int[height.length];
        leftMax[0] = height[0];
        rightMax[height.length-1] = height[height.length-1];

        //使用一个rightMax来存储i往右的最大高度柱子 使用一个leftMax来存储i往左边的最大高度柱子
        for(int i=1,j=height.length-2;i<height.length && j>=0;i++,j--){
    
    
            leftMax[i] = Math.max(height[i],leftMax[i-1]);
            rightMax[j] = Math.max(height[j],rightMax[j+1]);
        }
        for(int i=1;i<height.length;i++){
    
    
            int min = Math.min(leftMax[i],rightMax[i]);
            if(min - height[i]<=0)//每个格子能积多少水
                continue;//不能积水
            else  res += min-height[i];
        }

        return  res;

    }

}

ここに画像の説明を挿入

解決策4:ダブルポインターメソッドダブルポインター
を使用します。メソッド2では、どの値がトラバース方向を決定しますか。

  • たとえば、右側の値が大きい場合、左側の列の水蓄積単位を計算できます。
    左側のものが小さいので、左側に水単位がある可能性が高いことがわかり
    ます。右側のポインターは移動せず、左側のポインターは移動します。列を計算した後
  • 逆に、左のポインタは移動せず、右のポインタは移動します
class Solution {
    
    
    public int trap(int[] height) {
    
    
        //一个格子一个格子的计算其上的积水单位
        if(height==null ||height.length<3) return 0;

        int res = 0;

       int left = 0;int right = height.length-1;
       int leftMax = height[0],rightMax=height[right];
       //双指针
       while(left<right){
    
    
           //判断哪个大
           if(height[left]<height[right]){
    
    
               //我们则计算左边的柱子的积水
               if(height[left]>leftMax ){
    
    //没有积水,当前的left柱子上
                    leftMax=height[left];

               }else//有积水
                    res+=leftMax-height[left];

                //左边指针移动一位
                  left++;

           }else{
    
    
                //我们则计算右边的柱子的积水
               if(height[right]>rightMax ){
    
    //没有积水,当前的right柱子上
                    rightMax=height[right];

               }else//有积水
                    res+=rightMax-height[right];

                //右边指针移动一位
                  right--;
           }
       }
        return  res;

    }

}

ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/qq_44861675/article/details/114706056