- 掘金团队号上线,助你 Offer 临门! 点击 查看活动详情
本题核心
不管思考过程多长,解出来以后,发现殊途同归。
题目描述
给你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
提示:
n = height.length
2 <= n <= 3 * 104
0 <= height[i] <= 3 * 104
解题代码
两天的解法演变过程,从二分->双循环->双指针
一开始想到的是用单循环找出整个数组最大值,然后在通过最大值将数组分为2个数组,
分别进行检索,找出面积最大的步长。然后代码执行错误。
public int maxArea(int[] height) {
int maxTag = 0;
int maxValue = 0;
for (int i = 0; i < height.length; i++) {
if (maxValue < height[i]) {
maxValue = height[i];
maxTag = i;
}
}
int maxSize = 0;
int maxStep = 0;
int minValue = 0;
if (height.length - maxTag > maxTag) {//还能向右
for (int i = maxTag + 1; i < height.length; i++) {
int step = i - maxTag;//跨度
if (Math.min(maxValue, height[i]) * step > maxSize) {
maxSize = Math.min(maxValue, height[i]) * step;
minValue = height[i];
maxStep = step;
}
}
} else {
for (int i = 0; i < maxTag; i++) {
if (Math.min(maxValue, height[i]) * i > maxSize) {
maxSize = Math.min(maxValue, height[i]) * i;
minValue = height[i];
maxStep = i;
}
}
}
return Math.min(maxValue, minValue) * maxStep;
}
接着想着暴力解,双循环
public int maxArea(int[] height) {
int w = 0;//
int h = 0;//
int maxSize = 0;//找出最大面积的 宽和高
for (int i = 0; i < height.length; i++) {
for (int j = 0; j < height.length; j++) {
int diffH = Math.min(height[i], height[j]);
int diffW = (j - i);
if (i < j && diffH * diffW > maxSize) {
w = diffW;
h = diffH;
maxSize = diffH * diffW;
}
}
}
return w*h;
}
但是双循环在遇到数组过大的时候会出现超时。
那么既要循环,又要找到2个左边界和右边界的话。那就只能用while循环了。
public int maxArea(int[] height) {
int maxSize = 0;//找出最大面积的 宽和高
int i = 0;//左指针
int j = height.length - 1;//右指针
while (true) {
if (i >= j) {//交叉
break;
}
int leftValue = height[i];
int rightValue = height[j];
int value = Math.min(leftValue, rightValue);
int size = value * (Math.abs(j - i));
if (size > maxSize) {
maxSize = size;
}
if (leftValue > rightValue) {//如果左边指针对应的value大于右边指针
j--;//移动右边的指针
} else {//移动左边的指针
i++;
}
}
return maxSize;
}
最后优化下代码
public int maxArea(int[] height) {
int maxSize = 0;//找出最大面积的 宽和高
int i = 0;
int j = height.length - 1;
while (i < j) {
int value = Math.min(height[i], height[j]);
maxSize = Math.max(value * (j - i), maxSize);
if (height[i] > height[j]) {
j--;
} else {
i++;
}
}
return maxSize;
}
看看题解了解下其他姐法
##总结
嘿嘿,作为经常做预防老年痴呆难度的醋君,今天挑战了下中级,也不过如此。哼(ˉ(∞)ˉ)唧
~骑士君,ヾ(◍°∇°◍)ノ゙加油啊