盛水最多的容器:我待算法如初恋(五)
前言
好吧,小菜鸡又来写算法啦! 刚刚写了一下力扣热题100道的第五道,就是之前我看了一眼说比较难的题(对我来说),因为他那个官方解题太复杂了。然后我在b站上学习了一下,然后再看这道题目好像确实不是好难得样子。好吧,咱们开始上题目了。
手刃算法第六式:盛最多水的容器
给定一个长度为
n
的整数数组height
。有n
条垂线,第i
条线的两个端点是(i, 0)
和(i, height[i])
。找出其中的两条线,使得它们与x
轴共同构成的容器可以容纳最多的水。返回容器可以储存的最大水量。说明: 你不能倾斜容器。
拿到这道题目咱们先来分析一下题意:
题目分析
这道题目说的那么复杂,其实就是要咱们在一个数组里面找到两个数,使这两个数中较小的那个数与这两个数的下标差的乘积最大,并返回它俩的乘积。我当时看这个题目理解意思的时候以为是相邻的两条边,还是我把题目想的太复杂了。
理解了题意我们再来考虑,如何找这两个数呢?我们是不是首先想到的就是利用两个循环遍历,根据乘积的大小来确定这两个数。这就是我们常说的暴力枚举法,这种方法最简单,但是又是最烂的一种方法,因为它耗的时间是最多的,他的时间复杂度为O(n^2)。在这里还是给大家演示一下吧!
var maxArea = function(height) {
let maxarea = 0;
for(let i = 0; i < height.length; i++){
for(let j = i + 1; j < height.length; j++){
let area = Math.min(height[i],height[j])*(j-i)
maxarea = Math.max(maxarea, area);
}
}
return maxarea;
}
这个方法是没有什么问题,只不过最后需要的时间太多了,导致超出了时间限制。
那除了这个方法还有什么方法呢?
我们其实还可以从从两头开始找。因为我们是要找到两条边中的最短的那条使他们的乘积最大,所以我们就应该是要移动最短的那条边。 否则的话,我们固定最短的那条边那个乘积就会越来越小。这个大家应该可以想到吧?就相当于求面积,已经固定了最短的那条边,再一直减小另外一条边,那么面积肯定是越来越小的,所以就不能固定最短的那条边了。
去实现它
设置两个指针分别指向数组的头部和尾部,再设置一个最大值,然后判断这两个数的大小,将最小的数乘以他们的下标差,判断最大值与它们的乘积的大小,取最大值。最后再移动值最小的指针直到两个指针重合前。
具体的代码实现:
/**
* @param {number[]} height
* @return {number}
*/
var maxArea = function(height) {
let i=0;
let j=height.length-1;
let maxWater = 0;
while(i<j){
if(height[i]<height[j]){
maxWater=Math.max(maxWater,height[i]*(j-i));
i++;
}
else{
maxWater = Math.max(maxWater,height[j]*(j-i));
j--;
}
}
return maxWater;
};
代码内容还是较为简单的。不过要注意一下,我们尾部指针应该是height.length-1
,因为数组的下标是从0开始的。我就错了,别学我!
还有没有简单的方法?
找了好久的最优解还没有找到,但是找到个超过了99%的人,不过那个代码就一行,看不懂实在看不懂!我现在还没到那种程度,就不拿过来献丑了,如果感兴趣的可以去Leecode的题解那里看看看。
总结
这道题我感觉还是挺有趣的,听说这道题是道典型的滑动窗口问题,所以滑动窗口问题是啥呢?有两个边界的,需要试探的,就是典型的滑动窗口问题。其实当我们思路捋顺了,拿下它还是很简单的。加油!兄弟们!
转载自:https://juejin.cn/post/7397628739885826083