Leetcode第11题,盛水最多的容器:
给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。返回容器可以储存的最大水量。
示例:输入[1,8,6,2,5,4,8,3,7]时,输出为49。
根据题目和示例的理解,求存储的水量,其实是求上图中两条线构成的长方形最大的面积,也就是由两条线之间的距离构成的底 * 两个柱子中更矮的柱子的高。
在示例1中,当分别取值为8和7的两条线时,两条线的距离为7(在height数组中8的下标为1,7的下标为8,所以距离是7),高只能取较矮的线的高,因此面积为7X7=49。
看到这道题,我首先想到的解题思路是使用嵌套的For循环,作为中等难度得题目感觉有点略简单,但是提交后发现自己天真了...
For循环思路:定义一个int变量i遍历数组height中的每一个值作为右侧的高,同时在这层遍历内再定义一个int变量j,在每次i遍历到某个值时,j遍历从height[0]-height[i-1]作为左侧的高,由此穷举出所有可能得长方形,最后取面积最大的那个长方形的面积。
例如当i的值为8时,j的值可以为1、2、3、4、5、6、7,就有7个长方形
此时的代码为
执行代码,成功运行,准备提交收工,此时发现并没有通过leetcode的所有测试用例,由于此方法会遍历两次数组,所以时间复杂度比较高,为O(n²),当数组的数量非常非常大时,无法在合理的时间内计算结果。
原来这道题最有效的解法是通过双指针的方法,这样无需重复遍历数组,可以将时间复杂度降低到(O(n)),能使运算效率大大提升。
双指针思路:最开始在数组最左侧和最右侧分别定义指针,之后通过移动两侧指针的方式计算长方形的面积,通过while循环来持续的寻找新的长方形。
用示例给的数组,一开始两个指针分别在height[0] =1 和height[8] =7的位置:[1, 8, 6, 2, 5, 4, 8, 3, 7]
该长方形的面积为 min(1,7) * 8 =8。
此时需要移动指针来形成其他的长方形,需要移动左边的指针。 原因是左边指针的值更小,而更小的这个值决定了长方形的高,所以右边的指针不管怎么移动,面积都不会更大。
比如向左移动右指针到3的位置,新的长方形面积为min(1,3)*7=7,比之前的8更小了。
将左指针右移一位到8的位置,此时指针位置:[1, 8, 6, 2, 5, 4, 8, 3, 7],该长方形的面积为 min(8,7) * 7 =49,比之前的8更大了。
也就是说,我们移动指针前,先看指针对应的值谁更小,谁小就移动谁。
以此思路编写代码:
提交这段代码,成功通过。
看了下评论区, 发现果然大家想到的都是for循环......