原题目
Given n non-negative integers a1, a2, …, an, where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water.
Note: You may not slant the container and n is at least 2.
Subscribe to see which companies asked this question.
题目中文大意
给定n个非负整数a1,a2, …, an,其中ai可以作为第i个位置的木板高度,求在这么多个位置的木板中,找到两块木板,构成的水桶,盛到的水最多,并返回对应的水量。
思路
- 给定两个木板ai,aj(j>i),他们围成的木桶,装水量为min(ai,aj)*(j-i),水量的计算方式,这构成了本题的基础。可知,水量大小取决于两个模板的间隔以及最短的木板。
- 在这种情况下,最直接的做法是,用二层循环,将每一对木板都遍历一遍,求出对应的面积,通过比较求得最大水量。然而,这种方法的时间复杂度为O(n^2),超出了时间限制。
- 为了更加便捷地求出最大的出水量,可以从两头到中间进行遍历,但问题在于,在什么情况下,缩小木板的跨度。
- left,right分别为最左边,最右边的木板对应的下标,假设当前遍历到a[left],a[right], 假设较小的是a[left],那这时候如果要缩小跨度,应该从left端入手(将短木板换成长木板,才有可能取得更大的水量),因此left向右递增。
- 这样的遍历直到left==right终止。这样,最终的算法复杂度是O(n),不会超时
题解(O(n))
class Solution {
public:
int maxArea(vector<int>& height)
{
int n = height.size();
int left = 0;
int right = n-1;
int mostWater = -1;
while(left!=right)
{
int currWater;
if(height[left] > height[right])
{
currWater = height[right] * (right-left);
right--;
// if(height[right] < height[right+1])
// right --;
}
else
{
currWater = height[left] * (right-left);
left ++;
// if(height[left] < height[left-1])
// left++;
}
if(currWater > mostWater) mostWater = currWater;
}
return mostWater;
}
};
心得体会
在本周的leetcode中,一种很常见的做法是用两个下标来遍历数组,从而达到降低算法的时间复杂度的目的(比如之前的快慢指针,这道题的从左右到中间的遍历)。这种方法值得在日后的题目中使用。