计算水的容积_数组

思路:

对每一个格子,都计算其对应能容纳的水,即单独考察每一个位置,实际上能容纳多少的水。

比方说上面的例子,我们看 第2个位置,对应的高度为1,要计算这个位置实际上能容纳的水,只需要计算这个位置的左边部分的最高点,和右边部分的最高点,就能轻松计算出这个位置实际能容纳的水量了。 就是 3-1 = 2。

那么,对于每个位置,如何计算其左边部分最大值和右边部分最大值呢?

很简单,就是从左往右扫一遍,用一个数组记录当前的最大值即可。就能得到每个位置左边最大的值。

右边最大的值也同理。

代码如下:

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

int arr[1000];
//左边最大值的数组
int pre[1000];
//右边最大值的数组
int post[1000];

int main(){

	int N;
	scanf("%d",&N);
	for(int i=0;i<N;i++) scanf("%d",&arr[i]);
	
	pre[0] = arr[0];
	for(int i=1;i<N;i++)
		pre[i] = max(pre[i-1],arr[i]);
		
	post[N-1] = arr[N-1];	
	for(int i=N-2;i>=0;i--) 
		post[i] = max(post[i+1],arr[i]);
	
	int ans = 0;
	for(int i=0;i<N;i++){
		int min_ = min(post[i],pre[i]);
		ans += max(0,min_-arr[i]);
	}
	printf("%d\n",ans);
	return 0;
}

进阶版:

上述要用到两个辅助数组,如何做到不需要也能完成这个任务?

这里可以用双指针法,即用两个指针分别指向最左和最右两端。可以知道最左和最右两端肯定是留不下水的。所以遍历方式如下:

用指针i和j分别表示指向左和右的位置。而当两者指向同一个位置时,说明遍历结束。

每次遍历,比较i的位置和j的位置的大小:

若i比较小,则此时我们可以知道i+1位置的储水量我们是肯定可以计算出来的,因为此时已经知道i的高度是瓶颈,可以直接根据i位置的高度和i+1位置的高度进行计算。

若j比较小,同理,我们计算j-1位置的储水量,因为这个时候知道j的位置是瓶颈。

代码:

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

int arr[1000];
int main(){

	int N;
	scanf("%d",&N);
	for(int i=0;i<N;i++) scanf("%d",&arr[i]);
	
	int i=0,j=N-1; 
	int ans=0;
	//左边的最大值 
	int left_max = arr[i];
	//右边的最大值 
	int right_max = arr[j];
	while(i!=j){
		//此时左边是瓶颈 
		if (arr[i]<=arr[j]) {		
			i=i+1;
			left_max = max(left_max,arr[i]);
			ans+= max(0,left_max-arr[i]);
		}
		//此时右边瓶颈 
		else {
			j=j-1;
			right_max = max(right_max,arr[j]);
			ans+= max(0,right_max-arr[j-1]);			
		}
	}
	
	printf("%d\n",ans);
	return 0;
}