LeetCode(11):盛最多水的容器
Medium!
题目描述:
给定 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。画 n 条垂直线,使得垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
注意:你不能倾斜容器,n 至少是2。
解题思路:
我们需要定义i和j两个指针分别指向数组的左右两端,然后两个指针向中间搜索,每移动一次算一个值和结果比较取较大的,容器装水量的算法是找出左右两个边缘中较小的那个乘以两边缘的距离,代码如下:
C++参考答案一:
1 class Solution { 2 public: 3 int maxArea(vector<int>& height) { 4 int res = 0, i = 0, j = height.size() - 1; 5 while (i < j) { 6 res = max(res, min(height[i], height[j]) * (j - i)); 7 height[i] < height[j] ? ++i : --j; 8 } 9 return res; 10 } 11 };
下面这种方法是对上面的方法进行了小幅度的优化,对于相同的高度们直接移动i和j就行了,不再进行容量计算了,参见代码如下:
C++参考答案二:
1 class Solution { 2 public: 3 int maxArea(vector<int>& height) { 4 int res = 0, i = 0, j = height.size() - 1; 5 while (i < j) { 6 int h = min(height[i], height[j]); 7 res = max(res, h * (j - i)); 8 while (i < j && h == height[i]) ++i; 9 while (i < j && h == height[j]) --j; 10 } 11 return res; 12 } 13 };
使用贪心算法
1.首先假设我们找到能取最大容积的纵线为 i, j (假定i < j),那么得到的最大容积 C = min( ai , aj ) * ( j- i) ;
2.下面我们看这么一条性质:
①: 在 j 的右端没有一条线会比它高!假设存在 k |( j < k && ak > aj) ,那么 由 ak > aj,所以 min(ai, aj, ak) =min(ai, aj) ,所以由i, k构成的容器的容积C’ = min(ai, aj) * (k - i) > C,与C是最值矛盾,所以得证j的后边不会有比它还高的线;
②:同理,在i的左边也不会有比它高的线;这说明什么呢?如果我们目前得到的候选: 设为 x, y两条线(x< y),那么能够得到比它更大容积的新的两条边必然在[x, y]区间内并且 ax’ >= ax , ay’ >= ay;
3.所以我们从两头向中间靠拢,同时更新候选值;在收缩区间的时候优先从x, y中较小的边开始收缩;
C++参考答案三:
1 class Solution { 2 public: 3 int maxArea(vector<int>& height) { 4 int n=height.size(); 5 int i=0,j=n-1; 6 int max=0; 7 while(i!=j){ 8 if(height[i]<height[j]){ 9 int valid_height=height[i]; 10 int temp_area=valid_height*(j-i); 11 max=max>temp_area?max:temp_area; 12 i++; 13 } 14 else{ 15 int valid_height=height[j]; 16 int temp_area=valid_height*(j-i); 17 max=max>temp_area?max:temp_area; 18 j--; 19 } 20 21 } 22 return max; 23 } 24 };
C++参考答案四:
逼近法
每次左右两端都舍去短的那一端
若选择短的那一端【S=小于等于此端的高*小于等于当前的最大区间长度】,至多的面积也是选择最左最右的一个矩形,因此不必再考虑短的一端,直接舍去逼近
1 class Solution { 2 public: 3 int maxArea(vector<int>& height) { 4 int _m = 0, r = height.size()-1,l=0; 5 while (r > l) { 6 _m = max(_m, min(height[l], height[r])*(r - l)); 7 if (height[r] > height[l]) ++l; 8 else --r; 9 } 10 return _m; 11 } 12 };
通过设置两个指针,分别指向数组的头和尾,计算容器可以容纳多少水,然后比较头指针和尾指针对应的高度,矮的那个前进或后退一步(很好理解)。
python参考答案五:
1 class Solution: 2 def maxArea(self, height): 3 """ 4 :type height: List[int] 5 :rtype: int 6 """ 7 l = 0 8 r = len(height) - 1 9 contain = 0 10 while l < r: 11 contain = max(contain, (r - l) * min(height[l], height[r])) 12 if height[l] > height[r]: 13 r -= 1 14 else: 15 l += 1 16 17 return contain