题目
给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:你不能倾斜容器。
示例 1:
输入:[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
示例 3:
输入:height = [4,3,2,1,4]
输出:16
示例 4:
输入:height = [1,2,1]
输出:2
题目解析及优化
- 依旧先看暴力解决法;
用两个for循环暴力解法,代码就不贴了,意思都懂。 - 用双指针(真的想不到啊)
首先来思考一件事情,从上面的暴力法出发,看看有没有重复计算的或者无效计算的部分。
按第一个不简单也不复杂的例子来看吧。
先看有无重复计算的地方,从第一个柱子开始遍历,每次都和之后的所有柱子进行“盛水”,判断,需要和每个柱子判断才能无遗漏的判断。然后没有重复计算的地方。
再看看有没有无效计算的地方。-
还是从第一根柱子开始看,如果想获得以第一根柱子为一个边所能形成的最大容器,从感性上看,应该从两边入手,更能快捷的获得最大值。那么就直接找到了第9根柱子,形成的容器体积为8。此时我们发现第一根柱子恰好为最低的柱子,那么第9根柱子就是能和第一个柱子形成的最大容器。
-
是不是觉得很巧合。那么我们换根柱子再看。还是上面的例子。我们这次稍微改变一下,将第1根第2根柱子去掉。从第3根柱子开始。(此时其实为第1根柱子,为了方便,我们还是以第三根柱子去称呼)。
-
还是很感性的直接找第9根柱子,此时形成的最大容器的较低边是第三根柱子,最大体积为36。此时我们在向第8根柱子继续找的时候,想一想,后面的柱子有没有可能超过36。因为往里找的时候,容器的较低的边不可能超过6,同时底边也在变短,也就是说,再往里找的时候,体积肯定不超过36。换句话说,之后的都是无效计算。
-
我们再换个例子。将第一根柱子去掉,直接从第二根柱子开始。依旧直接找第9根柱子。此时体积为49。在往里寻找的时候,我们再思考思考,这次的情况变了,虽然往里找以第二根柱子为边的容器较高边可能找到比此时的较低边(第9根柱子)更高的边,但是眼光放在第9根柱子上,此时变成以第9根柱子为一边的最大容器了。
-
这样解释之后,发现了吗?找的时候直接以最两边的柱子形成容器,那么较低边的最大容器就找到了。就可以将这条边抛开了,往里扩张,重复知道剩下一根柱子即可。看了题目,再看了分析,应该知道双指针解法的由来了。这个解法是真的不好想。
其实仔细阅读就会发现作者的逻辑性不是很强,一直在用感性这个词。如果对证明过程感兴趣的,可以点这里。
心得及总结
- 对于暴力法的无效计算,可以先感性的去找合适的值,在每进行下一步之前想想哪些计算肯定是多余的(可能会难想一些,结合暴力法的顺序去观察),可能就会有奇效。
- 关于求解的方法可能就在分析之后就出来了,不必刻意去记每道题具体的解法,但是对方法的种类和使用方法要清楚。重要的还是思维。