LeetCode 42. Trapping Rain Water

本文通过LeetCode上的Trapping Rain Water难题,探讨了一种高效解决方案。文章首先介绍了作者初次尝试时采用的暴力求解方法及其存在的问题,随后提出了改进方案,采用两端向中间逼近的策略,最终实现了O(n)的时间复杂度。

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

第一次写博客,我这种水平的大学生程序猿为什么会想到要写博客这种东西呢,而且还要周更呢?没错,这是我们老师布置的作业鄙视。如果觉得我的博客写得有何不妥,请在下方留言,每周我会抽取幸运观众进行回复,谢谢大家。

进入正题,这是我们算法老师布置的作业,每周我将在LeetCode上抽取幸运题进行解答,并编写题解在博客上。打开LeetCode,因为我之前尝试过一道难度为中等的题,觉得还行,所以这一次我直接找了一道难度为hard的题,也就是这次我要讲解的题Trapping Rain Water 题目如下


大概意思就是给一个向量,告诉柱形图中每一个黑色的四边形的高度,然后向整个图从上到下注水,看能够盛多少水,一个正方形代表体积为1。英语比较好的同学请自行翻译。这道题我一看就想到了解决方法,那就是一层一层的暴力加。我们依靠上图的例题来解释一下。首先我们看第一层,从第一个小黑块开始,记录一下横坐标,一直到找到下一个小黑块,这两个小黑块中间的空隙长度水占的体积了,一直循环到向量的尾部,然后加第二层,第三层。写完后,加上测试代码,输入题目中的样例,输出正确。心想这种题的难道也能是hard,LeetCode不行啊。兴高采烈的提交后发现竟然超时了,亏我还故意优化了一下时间花费。当场懵逼。附上代码。

class Solution {
public:
    int trap(vector<int>& height) {
        int ans=0;
	int p=-1,q=-1;//记录横坐标
    for(int i=1;i<50000;i++)
    {	
		p=-1,q=-1;
    	for(int j=0;j<height.size() ;j++)
   		{
   	
   		if(height[j]>=i)
   		{
   			p=j;//将出现的第一个小黑块记录下来
   			if(q>=0)//如果这不是此行出现的第一个小黑块
   			{
			   ans+=p-q-1;//统计
			   q=p;//更新起点
			}
    		else
    		q=p;
		}

		}
		if(q<0)//如果一层只有一个或没有小黑块则结束
		break;
	}
	return ans;
    }
};
大概想了想时间复杂度,发现我的时间复杂度为O(nm)(m为向量中倒数第二大的数)。好吧,我的思路的确是有问题,如果说向量长度只有三,但是数都是十万多的话问题就很严重了,是十分不划算的。说实话这个时候我也懵了,不知所措。然后就只好转变方向,之前的方法是横向切割,一层一层计算,那么纵向切割呢,这样的话复杂度就是O(n)了,应该可以达到要求,那么问题来了,怎么统计水的体积。

一个很简单的模型,如果两端都有高度为a的黑方条,那么这两个黑方条之间的空间是可以注满水的,现在我们向里面的这个空间填一些小方块,填一个小方块的话在其竖直方向的水就会少一体积,如果说我放的小方块过多而超出了水面呢?设这一很长的条横坐标为t,高度为b,考虑t的右边部分,这一部分的右端高度为a,左端高度为b,根据木桶原理在这两端之间的部分高度为a是可以全部装水的。那么在此区间内再次出现一个高度为c的长条呢?b>c>a那么b和c这一段又是刚才的模型了,利用计算机最擅长的迭代就可以解决啦。

int trap(vector<int>& height) {
	int ans=0;
	int l=0;//左端点
	int r=height.size()-1;//右端点
	int m=0;//记录当前最矮的小黑条
	while(r>l)
	{
		if(height[l]<=m)
		{
			ans+=m-height[l];
			l++;
		}
		else if(height[r]<=m)
		{
			ans+=m-height[r];
			r--;
		}
		else
			m=min(height[l],height[r]);
	}
	return ans;
}
从两端开始,记录一个当前最矮的,也就是木桶原理中的短板,如果说靠近端点的小黑条的高度低于或齐平,就可以进行一次统计并更新端点,所以判断条件中的等于很重要,要不然是不会更新端点的。循环就有可能陷入死循环。如果在内部出现了一个更高的小黑条区间的话我们就重新记录短板,并在此区间继续上述操作。直到区间长度为0结束,这时我们的统计也完成了。
---------------------------------------------手动分割线-----------------------------------------

see you next illusion



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值