备战秋招-LeetCode 打卡-接雨水(暴力枚举、暴力优化、双指针)

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

在这里插入图片描述

上面是由数组 [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

题目链接(LeetCode)

思路一:暴力法
其实刚看到这道题暴力法也有点麻烦,因为不知道怎么去暴力。每一个位置积水的高度=左右两边高度的最小值 - 该位置的高度,这个可以理解的话就很容易了。我们可以遍历每一个高度,求左边的最大值和右边的最大值,求得每一个位置的积水累加便可。时间复杂度为O(n^2)。

暴力法-参考代码:

class Solution 
{
    //暴力法
    public int trap(int[] height) 
	{
		int ans=0;
		//遍历每一个高度
		for(int i=0;i<height.length;i++)
		{
			//求该位置左右两边的最大值
			int leftMax=height[i];
			int rightMax=height[i];
			for(int j=i-1;j>=0;j--)
				leftMax=Math.max(leftMax, height[j]);
			for(int j=i+1;j<height.length;j++)
				rightMax=Math.max(rightMax, height[j]);
			//累加每个位置的积水
			ans+=Math.min(leftMax, rightMax)-height[i];
		}
		return ans;
    }
}

思路二:利用类似前缀和的思想对暴力法进行优化
暴力法的复杂度主要来源于遍历每一个位置和求左右两边的最大值,遍历每一个位置这个是没有办法优化的,只能从求左右两边的最大值上优化。由于每个位置左右两边的最大值时固定不变的。所以我们可以直接利用类似前缀和思想的方法先将它们存到数组里。遍历每个位置的时候直接取出来。时间复杂度可降为O(n)。

暴力法优化-参考代码:

class Solution {
    //暴力法的优化
	public int trap(int[] height) 
	{
		//记录数组记录每个位置左边的最大值
		int[] leftMaxs=new int[height.length];
		int lMax=0;
		for(int i=0;i<height.length;i++)
		{
			if(height[i]>lMax)
				lMax=height[i];
			leftMaxs[i]=lMax;
		}
		//记录数组记录每个位置右边的最大值
		int[] rightMaxs=new int[height.length];
		int rMax=0;
		for(int i=height.length-1;i>=0;i--)
		{
			if(height[i]>rMax)
				rMax=height[i];
			rightMaxs[i]=rMax;
		}
		//统计每个位置能放多少雨水
		int ans=0;
		for(int i=0;i<height.length;i++)
			ans+=Math.min(leftMaxs[i], rightMaxs[i])-height[i];
		return ans;
    }
}

思路三:双指针
我们每次求一个位置的积水,都要考虑左右两边的最大值。如果我们确定了右边的最大值大于左边的最大值,便可以只考虑左边的最大值。反之同理。有点难理解,直接上核心代码

核心代码:

//遍历所有的位置
while(left<right)
		{
			//当左指针对应的高度比右边的低时,需要考虑左边的最大值
			if(height[left]<height[right])
			{
				//当左指针对应的高度大于左边的最大值,不可能会有水,更新左边的最大值
				if(height[left]>leftMax)
					leftMax=height[left];
				//否则求该位置能装的水
				else
					ans+=leftMax-height[left];
				left++;
			}
			//与上同理
			else
			{
				if(height[right]>rightMax)
					rightMax=height[right];
				else
					ans+=rightMax-height[right];
				right--;
			}
		}	
		return ans;

双指针-参考代码:

class Solution
{
    //双指针
	public int trap(int[] height) 
	{
		if(height.length<=1)
			return 0;
		int ans=0;
		int left=0,right=height.length-1;//左右指针
		int leftMax=height[0],rightMax=height[height.length-1];//指针位置左右两边的最大值
		while(left<right)
		{
			//当左指针对应的高度比右边的低时,需要考虑左边的最大值
			if(height[left]<height[right])
			{
				//当左指针对应的高度大于左边的最大值,不可能会有水,更新左边的最大值
				if(height[left]>leftMax)
					leftMax=height[left];
				//否则求该位置能装的水
				else
					ans+=leftMax-height[left];
				left++;
			}
			//与上同理
			else
			{
				if(height[right]>rightMax)
					rightMax=height[right];
				else
					ans+=rightMax-height[right];
				right--;
			}
		}	
		return ans;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值