【LeetCode】Trapping Rain Water

本文介绍了一种计算给定地形最多能捕捉多少雨水的算法。通过两次遍历数组,分别记录左侧和右侧最高点,进而计算每个位置能容纳的水量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考链接


http://blog.youkuaiyun.com/doc_sgl/article/details/12307171

http://blog.youkuaiyun.com/wzy_1988/article/details/17752809


类似题目

题目描述

Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining.

For example, 
Given [0,1,0,2,1,0,1,3,2,1,2,1], return 6.


The above elevation map is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped. Thanks Marcos for contributing this image!


目分析

题目很简单,就是把给出的组想像的木板,看下雨后最多可以容多少水。

思路: 对于数组,要想到可以从头遍历,也可以从尾遍历。


思路一:自己想的
思路见代码注释

思路二:网上常见思路

对某个值A[i]来说,能trapped的最多的water取决于在i之前最高的值leftMostHeight[i]和在i右边的最高的值rightMostHeight[i](均不包含自身)。

如果min(left,right) > A[i],那么在i这个位置上能trapped的water就是min(left,right) – A[i]。

有了这个想法就好办了,第一遍从左到右计算数组leftMostHeight,第二遍从右到左计算rightMostHeight。

时间复杂度是O(n)。

对于每个A[i]能trapped water的容量,取决于A[i]左右两边的高度(可延展)较小值与A[i]的差值,即volume[i] = [min(left[i], right[i]) - A[i]] * 1,这里的1是宽度,如果the width of each bar is 2,那就要乘以2了

总结


代码示例

#include <iostream>
#include <vector>
using namespace std;

#if 0
class Solution {
public:
    int trap(int A[], int n) {
    	int leftIndex = 0, rightIndex = n-1;
        
        int sumWater = 0;
        while(!A[leftIndex] && leftIndex<n)leftIndex++;	//找到左侧第一个非0 
        if(leftIndex == n)	return 0;	//全部为0 返回0 
        while(!A[rightIndex])rightIndex--;	//打到右边第一个非0 
        if(leftIndex == rightIndex || rightIndex == leftIndex+1)	
			return 0;//如果左右非0是同一个地方,或者相差一个位置,那个返回0 
        
        int maxLIndex = leftIndex, MaxRIndex = rightIndex;
        sumWater = 0;
        int tmpWater = 0;
        //printf("sumWater = %d\n",sumWater);
        //从左向右遍历一遍。 
        for(int i = leftIndex+1;i<=rightIndex;i++)
    	{
    		if(A[i] >= A[maxLIndex])//如果当前值超过之前记录的最大值,那个做一个总结 
    		{						// sumWater += (A[maxLIndex]*(i-maxLIndex-1) - tmpWater);
    			sumWater += (A[maxLIndex]*(i-maxLIndex-1) - tmpWater);
    			maxLIndex = i;
    			tmpWater = 0;
    			//printf("%d:sumWater = %d\n",i,sumWater);
			}
			else
			{
				tmpWater += A[i];//这里的A[i]肯定小于 A[maxLIndex],所以A[i]代表的地方不能装水,后面需要减去 
				//printf("%d:tmpWater = %d\n",i,tmpWater);
			}
		}
		//同理需要从后再向左遍历一遍 
		tmpWater = 0;
		for(int i = rightIndex-1;i>=maxLIndex;i--)
    	{
    		if(A[i] >= A[MaxRIndex])
    		{
    			sumWater += (A[MaxRIndex]*(MaxRIndex-i-1) - tmpWater);
    			MaxRIndex = i;
    			tmpWater = 0;
    			//printf("%d:sumWater = %d\n",i,sumWater);
			}
			else
			{
				tmpWater += A[i];
				//printf("%d:tmpWater = %d\n",i,tmpWater);
			}
		}
		return sumWater;
    }
};
#elif 1
class Solution {
public:
    int trap(int A[], int n) {
        // Note: The Solution object is instantiated only once.
        if(A==NULL || n<1)return 0;
    	
		int maxheight = 0;
		vector<int> leftMostHeight(n);
		for(int i =0; i<n;i++)
		{
			leftMostHeight[i]=maxheight;
			maxheight = maxheight > A[i] ? maxheight : A[i];
		}

		maxheight = 0;
		vector<int> rightMostHeight(n);
		for(int i =n-1;i>=0;i--)
		{
			rightMostHeight[i] = maxheight;
			maxheight = maxheight > A[i] ? maxheight : A[i];
		}

		int water = 0;
		for(int i =0; i < n; i++)
		{
			int high = min(leftMostHeight[i],rightMostHeight[i])-A[i];
			if(high>0)
				water += high;
		}
		return water;
    }
};
#endif

void test0()
{
	int A[] = {0,1,0,2,1,0,1,3,2,1,2,1};
	Solution so;
	if(so.trap(A,12) != 6)
		printf("------------------------failed\n");
	else
		printf("------------------------passed\n");
}
void test1()
{
	int A[] = {2,0,2};
	Solution so;
	if(so.trap(A,3) != 2)
		printf("------------------------failed\n");
	else
		printf("------------------------passed\n");
}
int main(int argc, char *argv[])
{
	test0();
	test1();
	return 0;
}




推荐学习C++的资料

C++标准函数库
在线C++API查询
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值