leetcode接雨水

1.动态规划

可以发现当height中存在一些坑时,才可以接雨水;对Height[i],其能够接雨水意味着其左边两边必定有坑的边界,能够接多少雨水取决于坑的边界的值

对于height[i],记录其左边最大的值left[i]和右边最大的值right[i],则边界的高度为二者的最小值num=min(left[i],right[i])

height[i]能接的雨水量是num=height[i]

代码如下:

class Solution {
public:
	int trap(vector<int>& height) {
		int n = height.size();
		// left[i]表示i左边的最大值,right[i]表示i右边的最大值
        //left[i],right[i]即表示当height[i]可以接雨水时,其左右两边的高度
		vector<int> left(n), right(n);
		for (int i = 1; i < n; i++) {
			left[i] = max(left[i - 1], height[i - 1]);
		}
		for (int i = n - 2; i >= 0; i--) {
			right[i] = max(right[i + 1], height[i + 1]);
		}
		int water = 0;
		for (int i = 0; i < n; i++) {
			int level = min(left[i], right[i]);
			water += max(0, level - height[i]);
		}
		return water;
	}
};

2.双指针

上述方法需要o(n)的额外空间

可以通过设置left,right指针来代替两个数组,这里的关键是何时更新left,right指针

left是从左到右遍历,right是从右到左遍历,且我们知道对于元素height[i],其左边的最大值max_left=max(max_left,height[i-1]),即height[left-1]可能成为max_left,

同理,可得height[right+1]可能成为max_right

只要保证height[left-1]<height[right+1],则max_left一定小于max_right.理由如下:

因为max_left是由height[left-1]更新过来的,且height[left-1]<height[right+1],而height[right+1]会更新max_right,所以必定有max_left<max_right

反之,就从右到左

代码如下:

class Solution {
public:
	int trap(vector<int>& height) {
    if(height.size()==0)
       return 0;
	int sum=0;
    int max_left=0;
    int max_right=0;
    int left=1;
    int right=height.size()-2;
    for(int i=1;i<height.size()-1;i++)
    {
        if(height[left-1]<height[right+1])
        {
            max_left=max(max_left,height[left-1]);
            sum+=max(0,max_left-height[left]);
            left++;
        }
        else
        {
            max_right=max(max_right,height[right+1]);
            sum+=max(0,max_right-height[right]);
            right--;
        }
    }
    return sum;
	}
};

3.观察法

可以发现接过雨水之后,整个数组像山字形一样,只有一个最大值,在该最大值左边数组是不严格递增,右边是不严格递减

只需要计算改变前后的差值,即是接雨水的值。

代码如下:

class Solution {
public:
	int trap(vector<int>& height) {
    int len=height.size();
    if(len==0)
      return 0;
    int num=height[0];
    int pos=0;
    for(int i=0;i<len;i++)
	{
        if(height[i]>num)
        {
              num=height[i];
              pos=i;
        }
    }//寻找最大值的位置
    int sum=0,cur=height[0];
    for(int i=1;i<pos;i++)
    {
       if(height[i]<cur)
         sum+=cur-height[i];
        else
         cur=height[i];
    }
    cur=height[len-1];
    for(int i=len-2;i>pos;i--)
     {
       if(height[i]<cur)
         sum+=cur-height[i];
        else
         cur=height[i];
    }
    return sum;
    
	}
};

猜你喜欢

转载自blog.csdn.net/qq_38196982/article/details/105306789