思路
最开始想到的是暴力求解法,即以每一个元素为一边,计算它与另外n-1个元素分别组成的面积,取其最大值。
以第一个元素为一边,遍历n个-1元素。然后以第二个元素为一边,遍历n-2个元素。以此类推,是以等差递减的次数遍历(1 + n) * n / 2次,时间复杂度是
O
(
n
2
)
O(n^2)
O(n2)。
这个答案会超时,因此得想想更快的方法。
假设两个边的下标分别是left和right,他们围成的面积就应该是它们之间的距离乘二者中更短的那个,即:
(
r
i
g
h
t
−
l
e
f
t
)
∗
m
i
n
(
h
e
i
g
h
t
[
l
e
f
t
]
,
h
e
i
g
h
t
[
r
i
g
h
t
]
)
(right - left) * min(height[left], height[right])
(right−left)∗min(height[left],height[right])
方便起见将其记为
a
r
e
a
=
d
(
距离
)
∗
m
i
n
(
最小值
)
area = d(距离) * min(最小值)
area=d(距离)∗min(最小值)。
要得到最大的面积,那么这两个因数就要越大越好。对于后者我们不方便找到两个元素作为基点去遍历数组,但对于前者,要取最大值很容易:数组的左右两端。
首先以数组首位下标为left,末位下标为right为起点,得到一个初始面积。此时如果想要继续增大面积,就得做其他尝试,即移动left或right。但无论移动哪一个,距离d都会缩小。如果移动的是二者中较长的那一个,min不会增大甚至还可能缩小,因此必须移动二者中较短的那个下标来增大min。
每次移动后如果新的面积大于旧的面积,就代表之前的端点可以被抛弃了,可以看做是找到了新的基点去遍历数组。最终左右相遇时得到的最大面积就是最终答案。由于每个元素只访问了一次,所以时间复杂度是 O ( n ) O(n) O(n)。
代码
// 双指针法
class Solution {
public:
int maxArea(vector<int>& height) {
// 左右两端
int left = 0, right = height.size() - 1;
int temp, max = 0;
while (left < right) {
temp = (right - left) * min(height[left], height[right]);
if (temp > max)
max = temp;
// 移动较短的那条边
if (height[left] < height[right]) {
left++;
}
else {
right--;
}
}
return max;
}
};
615

被折叠的 条评论
为什么被折叠?



