先看一下题目
题目说的是给定一个数组,将数组中的每个数作为一个Y值,其对应下标号(从1开始)作为X值,从该点下拉一条竖线到X轴,将这条竖线作为一个木板,求出由两条竖线和它们之间的X轴做成的水桶的最大容积。
这个问题牵扯到短板问题,即,一个木桶的最大容积是由围成它的最短的木板所决定的。因此对于本题来说,容积公式应该为:
V = the lowest height * x
解决这个问题首先想到的自然是暴力算法,即做两层循环遍历,获得最大面积。这种算法复杂度是O(n²),显然是效率最差的算法。
针对算法的优化,我经过找规律以及查看相关算法介绍,找到了一个不错的算法。
具体做法是,在数组的头和尾各准备一个指针,每次将两个指针所指的值作为木桶两侧的板子来考虑,接下来选取值较小的那个指针,将其做向另外一个指针靠近的操作,这里是因为:
对于较大值的高度其实并没有考虑到,容积是高度和长度的乘积,单独追求单方面的最大化是无法获得最大容积的
指针的移动实际上是意味着水桶底部的面积变小,要想获取最大值必须保证水桶的最短板高度变长,之前参考的较短板肯定不能再考虑,而较高板没有被考虑,所以不能被忽略,因此只能移动较短板的指针
当然,题目给的是非负整数,因此包含0,对于这个题目来说,0是没有意义的,因此必须得排除。
算法清晰了,那么接下来代码编写也就很容易了:
int maxArea(vector<int>& height) {
int max = 0;
int tempArea = 0;
int posL = 0;
int posR = height.size() - 1;
while (posL != posR) {
if (height[posL] == 0 || height[posL] <= height[posR]) {
if (height[posL] != 0) {
tempArea = height[posL] * (posR - posL);
if (max < tempArea)
max = tempArea;
}
posL++;
} else {
if (height[posR] != 0) {
tempArea = height[posR] * (posR - posL);
if (max < tempArea)
max = tempArea;
}
posR--;
}
}
return max;
}
这里对数组仅仅进行了一次遍历,因此算法复杂度为O(n),算是一个不错的优化