【力扣刷题记 11】——《盛最多水的容器》

218 阅读4分钟

Offer 驾到,掘友接招!我正在参与 2022 春招打卡活动,点击查看活动详情

一、题目描述:

  1. 盛最多水的容器-难度中等

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。

找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

返回容器可以储存的最大水量。

说明:你不能倾斜容器。

 

示例 1:

image.png

输入:[1,8,6,2,5,4,8,3,7] 输出:49 解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

示例 2:

输入:height = [1,1] 输出:1  

提示:

n == height.length

2 <= n <= 10^5

0 <= height[i] <= 10^4

二、题目和思路分析:

这道题我觉得很容易,因为看完题目我是这么想的:

假设最大容积的两条垂线是height[i]和height[j]

则容器的值实际上就是x轴和短的那条线的乘积,即

(j-i)*height[i] 或 (j-i)*height[j]

然而我按着遍历的方法写完了代码,提交才发现测试用例给了一个巨长、巨大的数组。

都怪我没有认真看提示:

提示:

n == height.length

2 <= n <= 10^5

0 <= height[i] <= 10^4

看来遍历的方法不可行,说明要取更优解。

那么更优解有哪些特征呢?

我想了半天,想的头发都开始摇摇欲坠了,终于想到了那么一点点门道。

  1. 更优解肯定不是全部都进行计算再比较

  2. 更优解也需要把全部数据遍历一遍

  3. 更优解应该是预先判断结果是否会大于当前结果,有的计算,有的跳过

那么根据这些条件怎么想呢???

我又想了半天,头发终于坚持不住的时候,我想到了确定的值是x轴的长度,height.length,同时它是个变量,即height[j]-height[i]。

这时候我们可以用它去乘height[j]或height[i],不断循环即可同样遍历出所有数据。

大概是这么个意思,但我受限于一个不太聪明的大脑,又无法把每个细节每个逻辑想的清清楚楚明明白白。

啊啊啊,先写代码吧!!!

就这样,我写着,改着,想着,调试了一个多小时,终于写出来了!!!

还好思路是对的,不然淦到通宵也没结果。

三、代码:

代码实现如下:

/**
 * @param {number[]} height
 * @return {number}
 */
var maxArea = function(height) {
    // 假设最大容积的两条垂线是height[i]和height[j]
    // 则容器的值实际上就是x轴和短的那条线的乘积,即
    // (j-i)*height[i] 或 (j-i)*height[j]
    // let max = 0
    // for(let i = 0; i<height.length; i++){
    //     for(let j = i+1; j<height.length; j++){
    //         let h = height[i] > height[j]? height[j] : height[i]
    //         let sum = (j-i)*h
    //         max = sum > max? sum : max
    //     }
    // }
    // return max

    // 遍历的方法不可行,说明要取更优解
    // 更优解有哪些特征呢?
    // 更优解肯定不是全部都进行计算再比较
    // 更优解也需要把全部数据遍历一遍
    // 更优解应该是预先判断结果是否会大于当前结果,有的计算,有的跳过
    
    // 那么怎么想呢
    // 确定的值是x轴的长度,height.length,同时它是个变量,即height[j]-height[i]。
    // 这时候我们可以用它去乘height[j]或height[i],不断循环即可同样遍历出所有数据

    let i = 0, j = height.length-1, minH = 0, max = 0
    while(i < j){ // 两端开始向中间循环
        if(height[i] < height[j]){ // 如果左边高度小于右边
            minH = height[i]  // minH取 height[i],左边向右移动
            max = Math.max(((j-i) * minH), max)
            i++
            while(minH > height[i]){ // 如果移动后的高度还没当前高度高,那么不需要计算,继续移动
                i++
            }
        }else{ // 如果右边高度小于左边,或两边相等
            minH = height[j] // minH取 height[j],右边向左移动
            max = Math.max(((j-i) * minH), max)
            j--
            while(minH > height[j]){ // 如果移动后的高度还没当前高度高,那么不需要计算,继续移动
                j--
            }
        }
    }
    return max 
};

四、总结:

今天是工作日,虽然不加班,但还是觉得时间不够用似的。

我本以为上一道题,也就是第十题就很难了,昨天搞了大半天也没搞出来,看了看别人的解题思路还是一头雾水,又看了好几遍才看出那么一点意思来,自己还是写不出。哪想到今天这道题也能写将近两个小时呢?

主要还是逻辑把握不住,想到一定深度大脑就像是卡死了,只能写一点看一点。另外细节还是容易漏掉,比如i++之后调用i,已经不是原先的i了,这点在我调试的时候,半天没看出来,还以为是自己思路不对。

嗐,世界上聪明的人那么多,可惜我不是其中一个。

加油吧!