Leetcode 热题100 42.接雨水(C++ 多种解法,错过可惜)

1、题目描述

Leetcode 热题100 42.接雨水(C++ 多种解法,错过可惜)_第1张图片

这是博主今天的Leetcode 每日一题——接雨水(困难),这道题做了一天也没有做出什么花样来,最后看了题解后,发现居然有那么多种解法,但是自己一个也没有想到,真的是被自己菜哭的一天 ,博主就根据自己的理解,写了这篇题解,希望对其他的小伙伴有所帮助。(插一句题外话,之所以写这篇题解,是因为它的解法很多,个人感觉很有价值,也有助于博主日后的再巩固,提供方便)话不多说,我们来看看,几种解法。(博主个人的理解哦)

2、题解集

2.1暴力解法

首先,暴力解法是一定是超时(自己已经试过了),如果不想看的小伙伴可以自动跳过,但是,博主在这里依然要写这种方法的原因是有的时候,我们可能想不到正解,只能通过题意或者自己的理解写出超时的代码(有的甚至都写不出来),但是这在样的代码上如果有优化,有可能就是正确解!那么就让我们来看看暴力解法的具体实现吧

①:我们枚举数组中的每一个元素,以该元素为分界线,找出其左边的最大值(left_max),再找出其右边的最大值(right_max),然后求left_max和right_max中的最小值。(为什么求最小值,就像木桶原理一样,最短的木板决定了,木桶最终的盛水量,后面的题解中也是这个意思,就不再解释)

②:我们将求得的最小值-该元素的值,即为该处的积水量,然后用ans来累加记录。

代码展示:

class Solution {
public:
    int trap(vector& height) {
     int n=height.size();
     if(n==1)
     return 0;
    int ans=0;
     for(int i=1;i=0;j--)//以该元素为分界线找左边的最大值
        {
            left_max=max(left_max,height[j]);
        }
        for(int j=i;j

2.2动态编程

 对于动态编程的思想,博主个人觉得就是对暴力解法的进一步优化,我们都知道暴力解法是求一个元素左边的最大值与右边的最大值,求两者之间的最小值,再与该元素求差,作为该处的积水量,而在动态编程中:

①:我们首先用两个动态数组left_max[],right_max[],分别保存从左到右(和从右到左的),每个元素左边的最大值(右边的最大值)。

②:然后再通过遍历一遍数组,比较每个元素对应的min(left_max[],right_max[])-该处的元素值,就是该处雨水的积水量,最后用ans来累加即可,这样我们就把O(n*n)的时间复杂度将为O(n)了。

③:至于left_max[],right_max[]的求解,博主个人感觉有点求“前缀和”和“后缀和”的感觉,只不过对于left_max[],right_max[]来说,是求比较后的最大值,而不是累加和;

代码展示

class Solution{
    public:
    int trap(vector& height){
        int n=height.size();
        if(n==1)
        return 0;
        int ans=0;
        vectorleft_max(n),right_max(n);//定义好两个动态数组
        left_max[0]=height[0];//保存left_max[]的第一个值
        for(int i=1;i=0;i--)//一次将right_max[]的每个元素赋值
        {
        right_max[i]=max(right_max[i+1],height[i]);
        }
        for(int i=0;i

2.3双指针

来啦来啦,双指针它来了,不得不的说双指针的解法真的很妙,怎么一个妙法呢?让我慢慢道来。

首先我们在动态编程的方法中知道,当left_max[i]right_max[i],积水量取决于right_max[i]的高度。所以我们可以这样理解,先用两个指针分别指向,原数组的头和尾(两端),对于其中某一元素,如果右端指针所指的值大,那么积水的高度就依赖于当前方向的高度(从左到右),如下图:

                                 right_max
 left_max                             __
   __                                |  |
  |  |__   __??????????????????????  |  |
__|     |__|                       __|  |__
        left                      right

 因为此时,从左到右的数对该数(left)来说是绝对可信的,而右边的数不一定,同理来说,当左端的数大时,那么积水的高度就依赖于当前方向的高度(从右到左),有了这样的思想我们就可以有一下的操作了:

①:定义left和right分别指向原数组的左右两端的下标;

②:用left_max,right_max分别保存左右两端的最大值;

③:如果,height[left]left_max,则更新left_max,否则left_max-height[left]保存积水量;若height[left]>=height[right],则判断 if height[right]>right_max,则更新right_max,否则right_max-height[left]保存积水量;

然后让我们来看看具体的代码实现吧。

代码展示

class Solution{//双指针
    public:
    int trap(vector& height){
        int n=height.size();
        if(n==1)
        return 0;
        int left=0,right=n-1;//左右边界
        int left_max=0,right_max=0;
        int ans=0;
        while(leftleft_max)
                {
                    left_max=height[left];//更新left_max;
                }
                else
                {
                    ans+=left_max-height[left];//计算该处的积水量
                }
                left++;//向右扫描
            }
            else//对该数的右边的数进行操作
            {
                if(height[right]>right_max)
                {
                    right_max=height[right];//更新right_max;
                }
                else
                {
                    ans+=right_max-height[right];//计算该处的积水量
                }
                right--;//向左扫描
            }
        }
        return ans;//返回积水量
    }
};

总结

这道题考到了好几种方法,我们的解题过程,解题方法也是一步一步的优化,一步一步递进的,博主个人觉得我们在平时的解题的时候也应该这样来做,总的来说这道题对我的收获也是很大的,如果有帮助到正在阅读的小伙伴,希望记得点赞、收藏哦!

你可能感兴趣的:(Leetcode题解,leetcode,c++,算法)