42.接雨水
https://leetcode-cn.com/problems/trapping-rain-water/
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例 1:
输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。
示例 2:
输入:height = [4,2,0,3,2,5]
输出:9
提示:
-
n == height.length
-
0 <= n <= 3 * 104
-
0 <= height[i] <= 105
代码及其实现
#include <stdio.h>
//接雨水
int min(int a,int b)
{
return a>b?b:a;
}
int trap(int* height, int heightSize){
if(heightSize <= 2)
{
return 0;
}
int left = 0;
int right = heightSize - 1;
int max_high = height[0];
int max_pos = 0;
for (int i = 1 ; i < heightSize;i++)//找到峰值最高的点,以它为标志点,从两边开始向它靠拢,因为我们知道它一定是一面合格的水池的墙
{
if (max_high < height[i])
{
max_pos = i;
max_high = height[i];
}
}//得到最高长度及其坐标
printf("############################left#################################\n");
int LR;
int all_height_l = 0;
int wall_size = 0;
while (left < max_pos)
{
while (left < max_pos && height[left+1] >= height[left])//找到能蓄水的池子的左墙 |__|
{
left++;
}
#if 0
|
|||
说明都是这种情况||||
#endif
if (left == max_pos)
{
break;
}
LR = left+1;//最终找到一堵比左墙矮的墙
while (LR <= max_pos && height[LR] < height[left])//找到下一堵墙,使之得能积水
{
LR++;
}
//以下是计算积水面积的公式,我们先计算出左右两面墙之间的墙体占的体积
for (int k = left;k <= LR;k++)
{
if (height[k] > min(height[left],height[LR]))//以两面墙的最小值来计算
{
wall_size += min(height[left],height[LR]);
}
else
{
wall_size += height[k];
}
}
//(LR - left+1)*min(height[LR],height[left]),左右墙形成的矩形,面积为两面墙的宽乘高(左右两高的较小高)
all_height_l += (LR - left+1)*min(height[LR],height[left]) - wall_size;//再减去实体墙占的空间,就得到水的面积
printf("wall_size: %d,all_height_l:%d\n",wall_size,all_height_l);
left = LR;
wall_size = 0;
}
printf("\n\n############################right#################################\n");
int RL;
int all_height_r = 0;
while (max_pos < right)
{
while (right > max_pos && height[right - 1] >= height[right])//这里right>max_po是对应height[right - 1] >= height[right],right>max_po保证了right-1>=max_pos
{
right--;
}
#if 0
|
|||
说明都是这种情况 |||||
#endif
if (right == max_pos)
{
break;
}
RL = right-1;
while (RL >= max_pos && height[RL] < height[right])//我们知道max_pos一定为合格的墙,所以RL可以等于max_pos,当它等于max_pos时说明它是最后一个洼地
{
RL--;
}
for (int k = RL;k <= right;k++)
{
if (height[k] > min(height[right],height[RL]))
{
wall_size += min(height[right],height[RL]);
}
else
{
wall_size += height[k];
}
}
all_height_r += (right - RL+1)*min(height[RL],height[right]) - wall_size;
printf("wall_size: %d,all_height_r:%d\n",wall_size,all_height_r);
right = RL;
wall_size = 0;
}
return all_height_r + all_height_l;
}
int main()
{
//int height[] = {4,2,0,3,2,5};
//int height[] = {0,1,0,2,1,0,1,3,2,1,2,1};
//int height[] = {0,2,0}; //ok
//int height[] = {4,2,0,3,2,5,4,2,0,3,4};
int height[] = {
4,2,0};
int heightSize = sizeof(height)/sizeof(height[0]);
int ret = trap(height,heightSize);
printf("\n\n\nresult:%d\n",ret);
return 0;
}
这种题,从逻辑角度算不上难,但是从手敲代码来看,很复杂,如何用一个统一的代码去将这个简单的逻辑实现,去完成所有的测试用例,那么就比较复杂了。
思考步骤
1.首选,我们先从给定的墙坐标中,找到最高的墙及其所处的位置
int max_high = height[0];
int max_pos = 0;
for (int i = 1 ; i < heightSize;i++)//找到峰值最高的点,以它为标志点,从两边开始向它靠拢,因为我们知道它一定是一面合格的水池的墙
{
if (max_high < height[i])
{
max_pos = i;
max_high = height[i];
}
}//得到最高长度及其坐标
以上代码,我们就能找到最高的墙的坐标位置max_pos,我们为什么要找到它?因为我们的积水条件,是,我们必须有洼地,必须有两面墙之间形成洼地。所以找到最高的墙,就能保证我们积水形成所需要两面墙的一面已经有把握了。
扫描二维码关注公众号,回复:
13128556 查看本文章
这样,我们从左边到max_pos开始,找所有的洼地,每找到一个洼地,我们就计算其积水面积,计算完成后,我们就接着找下一个,直到最后一个以max_pos为右墙的洼地。同理,从右边开始找洼地,直到最后一个以max_pos为左墙的洼地结束。