暴力解法与其局限
此题简单来说,就是给了一个数组,我们要将数组元素的值作为"墙",下标的距离为底,围成一个水缸,求得容积最大的那个。
先说暴力解法。
这很简单,容积等于底乘以高,给两个指针,依次遍历所有组合,依次求容积,每次更新容积最大的那个即刻,代码如下:
cpp
int maxArea_bad(vector<int>& height) {
//遍历组合
int n = height.size();
int v = 0;
for (int i = 0; i < n; i++)
{
for (int j = i + 1; j < n; j++)
{
int w = j - i;//宽度
int h = height[i] > height[j] ? height[j] : height[i];//高度
if (v <= w * h)
{
v = w * h;
}
}
}
return v;
}
它的局限很明显------许多可排除的组合它都进行了遍历。
我们拿一个示例:
cpp
h = [2, 8, 6, 2, 5, 4, 8, 3, 7]
0 1 2 3 4 5 6 7 8
left此刻在0处,我们移动另一个指针right。
这时,你会发现,八个组合,每次用于计算的高都是left处的1,导致这些组合都被淘汰,原因很简单:容积的高受较矮的那个影响。
发现了这个就很好办了。
双指针优化
我们干脆把两个指针安排在两边,计算完了容积后,让较矮的那个移动往中间靠拢,不断更新容积。
比如组合(2,7)计算完后,更新更小的左边,left++,直接从(8,7)开始,因为如果计算(2,7)之间,底只会更短,而更新7那一边的话,就没有意义。比如,如果新的右边比左边更小,那容积会更小,如果比左边更大,那高度还是会依据左边。
这样一来,代码显而易见:
cpp
int maxArea(vector<int>& height)
{
int left = 0, right = height.size() - 1;
int w = 0;//宽
int v = 0;//体积
while (left < right)
{
w = right - left;
if (height[left] < height[right])
{
if (v < w * height[left])
{
v = w * height[left];
}
left++;
}
else
{
if (v < w * height[right])
{
v = w * height[right];
}
right--;
}
}
return v;
}
当然,我们可以使用更加简洁的写法:
cpp
int maxArea_better(vector<int>& height)
{
int left = 0, right = height.size() - 1, ret = 0, v = 0;
while (left < right)
{
v = (right - left) * (height[left] < height[right] ? height[left++] : height[right--]);
ret = max(ret, v);
}
return ret;
}