思路:
对每一个格子,都计算其对应能容纳的水,即单独考察每一个位置,实际上能容纳多少的水。
比方说上面的例子,我们看 第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;
}