Rain Water trapping接雨水(多种方法)

Sai Charan is a professional programmer such that whatever he finds interesting, he would immediately convert it into a problem and try to get an algorithm for it which is the stepping stone for solving a problem. He saw water stagnation infront of his house after a heavy rain. So, he got an idea to write a program to find the amount of water stagnated, which is the inspiration for this problem

Problem Description

You are given an iron bar which is of dimension 1 unit. Iron bars are placed in a particular format for each test case, You must display the maximum units of accumulation of water between the iron bars if rainfall has occured in that building.

You can refer to the below image for clear understanding of the problem

在这里插入图片描述

Input
"The first line of the input contains an integer T denoting the number of test cases
"The first line of each test case contains a single integer N denoting the total number of bars that can be arranged horizontally
The second line of each test case contains N space-separated integers A0, A1, …, AN-1 denoting the bars which are placed vertically one above the other at each place A0,A1…AN-1 respectively
Output
For each test case, output a single line containing a single integer max which contains the maximum units of accumulation of water assuming a unit as the place between alternate bars
Constraints
1≤ T ≤ 100
1≤N≤ 1000
1≤ A0,A1,…AN-1 ≤ 1000

Example
Input:
2
6
3 0 0 2 0 4
6
3 0 3 3 3 3
Output:
10
3

思路分析:

首先,先明白什么情况下可以接到雨水。
对于第i个柱子来说,当左边的柱子和右边的柱子都比第i个柱子高时,第i个柱子就可以接到雨水。
更进一步分析,对于第i个柱子,向左扫描到最长的柱子l,向右扫描到最长的柱子r,那么该柱子可以接水的高度为min(h[l],h[r])-h[i].
因此就会有一个想法:对于每个柱子,找到左边的最大高度柱子和右边的最大高度柱子,然后计算接雨水的高度,接雨水的总体积就是每个柱子接到的雨水加起来。
这里可以想到用暴力扫描两边找最值,不过这样时间复杂度为O(n^2),一般都会超时。我们可以用dp打表,dp_left[i]表示第i个柱子左边最大值,dp_right[i]表示第i个柱子右边最大值,然后求出该柱子接水的高度。下面上dp代码。时间复杂度O(n),空间复杂度O(n).
方法一:dp

#include <iostream>
#define MAX 10010
using namespace std;

int h[MAX], dp_left[MAX], dp_right[MAX];

int main()
{
	int T, N;
	cin>>T;
	while(T--)
	{
		cin>>N;
		int ans = 0;
		for(int i = 0;i < N;i++) scanf("%d",&h[i]);
		dp_left[0] = h[0], dp_right[N-1] = h[N-1];
		for(int i = 1;i < N;i++)
		{
			dp_left[i] = max(dp_left[i-1], h[i]);
			dp_right[N-i-1] = max(dp_right[N-i],h[N-i-1]);
		}
		for(int i = 0;i < N;i++)
		{
			ans += (min(dp_left[i],dp_right[i])-h[i]);
		}
		cout<<ans<<endl; 
	}
	return 0;
}

另一种方法是维护一个单调递减栈。为什么会想到这个方法呢?因为接雨水是高一低一高,先递减后递增。对于一个单调递减栈的栈顶元素可以直接访问左边第一个比它大的元素。我们维护一个单调递减栈,遇到比栈顶高的柱子就可以比较栈顶左右的柱子高度算出接水高度。这个需要画图模拟一下,然后找到规律。下面直接单调栈的代码。
方法二:单调栈

#include <iostream>
#include <stack>
#define MAX 10010
using namespace std;

int main()
{
	int h[MAX];
	int T, N;
	cin>>T;	
	while(T--)
	{
		int ans = 0;
		stack<int> st;
		cin>>N;
		for(int i = 0;i < N;i++)
		{
			cin>>h[i];
			if(st.empty() || h[i] < h[st.top()])	//栈空或者高度比栈顶小,进栈 
			{
				st.push(i);
			}
			else
			{
				while(!st.empty() && h[i] >= h[st.top()])	//h[i]比栈顶高,一直出栈直到h[i]比栈顶小或栈空,保持栈的严格递减 
				{
					int tmph = h[st.top()];
					st.pop();
					if(!st.empty())	//若栈非空,累加接水体积 
					ans += (min(h[st.top()], h[i])-tmph)*(i-st.top()-1);
				}
				st.push(i);
			}			
		}
		cout<<ans<<endl;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值