盛最多水的容器:
给你 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线, 垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。 说明:你不能倾斜容器。
输入:[1,8,6,2,5,4,8,3,7] 输出:49 解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
提示:
看到这道题我最开始想到的还是直接两个for循环遍历得出最大值
public class Solution { public int maxArea(int[] height) { int ans = 0; for(int i = 0;i < height.length - 1;i ++){ for(int j = height.length - 1;j > i;j --){ int tmp = Math.min(height[i], height[j])*(j - i); ans = Math.max(tmp,ans); } } return ans; } }
不出所料的超时了
O(N2)
看了下官方的题解(自己还是做不出来orz)
运用了双指针的思路:
1.
将数组的第一个元素和最后一个元素设为最初的两个指针
双指针指向数组的左右边界,数组的所有元素都可以成为指针。
那么我们要如何移动这两个边界来计算出最大的面积呢?
2.
从上面的图我们会想到先移动左侧的指针向右侧一步,也就是两个指针指向的值更小的那一侧去移动,我们才可能得到更大的面积值。
证明以上思路的过程如下:
假设我们去移动更大的一侧的指针: 设左右边界的指针指向的数分别为 I1 和 J1,设 I1 < J1, 数组元素个数为 n,所包围的面积为 S ∴ S1 = min(J1, I1) * n = I1 * n; //最初所包围的面积 假设此时将右侧指针向左移动,指向的数为 j2 if(J2 >= J1) S2 = min(J2, I1) * (n - 1) = (I1 or J2) * (n - 1) < S1 else S2 = min(J2, I1) * (n - 1) = I1 * (n - 1) < S1 由此可知无论如何移动右侧指针 S 的值都不会比 S1大。
剩下的就是当两个指针重合时, 得出的最大面积就是我们的答案
代码如下
public class Solution { public int maxArea(int[] height) { int i = 0, j = height.length - 1; int max = 0; while (i != j) { int s = Math.min(height[j], height[i]) * (i - j); max = Math.max(max, s); if (height[j] <= height[i]) { j++; } else { i++; } } return max; } }
小感悟:第一次这么认真的做了一道题,之前断断续续的做过几道题但都不太精, 这个文章也写的很差,图画的很难看,这篇文章和这道题就算是我leetcode的一个全新的开始吧, 今后每道题都会写这么一篇文章,尽量跟上卷王们的步伐(哭