LeetCode:Container With Most Water,Trapping Rain Water

简介:

Container With Most Water

题目链接

Given n non-negative integers a1a2, ..., an, where each represents a point at coordinate (iai).n vertical lines are drawn such that the two endpoints of line i is at (iai) 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.


算法1:枚举容器的两个边界,时间复杂度O(n^2)。大数据超时

1
2
3
4
5
6
7
8
9
10
11
12
13
class  Solution {
public :
     int  maxArea(vector< int > &height) {
         int  res = 0, n = height.size();
         for ( int  i = 0; i < n; i++) //左边界
             for ( int  j = i+1; j < n; j++) //右边界
             {
                 int  tmp = (j-i)*min(height[i],height[j]);
                 if (res < tmp)res = tmp;
             }
         return  res;
     }
};

 

对上面的稍加改进,根据当前的已经计算出来的结果以及左边界的值,可以算出容器右边界的下界。不过还是超时

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class  Solution {
public :
     int  maxArea(vector< int > &height) {
         int  res = 0, n = height.size();
         for ( int  i = 0; i < n; i++) //左边界
         {
             if (height[i] == 0) continue ;
             for ( int  j = max(i+1, res/height[i]+i); j < n; j++) //右边界
             {
                 int  tmp = (j-i)*min(height[i],height[j]);
                 if (res < tmp)res = tmp;
             }
         }
         return  res;
     }
};

 

算法2:时间复杂度O(nlogn)。

构建结构体包含height和height在原数组中的位置

struct Node 
    { 
        int height; 
        int index;

};

对该结构体数组按照height的值递增排序,假设排序后的数组为vec.

 

假设f[i] 表示数组vec[i,i+1,…]内所有height按照原来的位置顺序排列好以后的最大水量

那么f[i-1]可以在O(1)时间内计算出来:因为vec[i-1].height 小于vec[i,i+1,…]内的所有height,所以以vec[i-1].index为边界的容器高度为vec[i-1].height,最大水量只需要分别计算vec[i,i+1,…]内按原始位置排列最前面和最后面的height,取两者的较大值。即下图中,黑色是最低的,要计算以黑色为边界的容器的最大水量,只需要分别和第一个和最后一个计算,去两者较大值

image

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class  Solution {
     struct  Node
     {
         int  height;
         int  index;
         Node( int  h, int  i):height(h),index(i){}
         Node(){}
         bool  operator < ( const  Node &a) const
         {
             return  height < a.height;
         }
     };
public :
     int  maxArea(vector< int > &height) {
         int  res = 0, n = height.size();
         if (n <= 1) return  0;
         vector<Node>vec(n);
         for ( int  i = 0; i < n; i++)
         {
             vec[i].index = i;
             vec[i].height = height[i];
         }
         sort(vec.begin(), vec.end());
         
         int  start = vec[n-1].index, end = start; //记录已经处理完的height的原始位置的左右端点
         for ( int  i = n-2; i >= 0 ; i--)
         {
             start = min(start, vec[i].index);
             end = max(end, vec[i].index);
             res = max(res, max(vec[i].height*(vec[i].index - start), vec[i].height*(end - vec[i].index)));
         }
         return  res;
     }
};

 

 

算法3:时间复杂度O(n),两个指针i, j分别从前后向中间移动,两个指针分别表示容器的左右边界。每次迭代用当前的容量更新最大容量,然后把高度小的边界对应的指针往中间移动一位。                                         本文地址

正确性证明:由于水的容量是有较小的那个边界决定的,因此某次迭代中,假设height[i] < height[j],那么j 减小肯定不会使水的容量增大,只有i 增加才有可能使水的容量增大。但是会不会有这种可能:当前的i 和 某个k (k > j)是最大容量, 这也是不可能的,因为按照我们的移动规则,既然右指针从k 移动到了j,说明i 的左边一定存在一个边界 m,使m > k,那么[m, k]的容量肯定大于[i, k],所以[i,k]不可能是最大容量。可以参考here

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class  Solution {
public :
     int  maxArea(vector< int > &height) {
         int  res = 0, n = height.size();
         int  left = 0, right = n-1;
         while (left < right)
         {
             res = max(res, (right-left)*min(height[left], height[right]));
             if (height[left] < height[right])
                 left++;
             else  right--;
         }
         return  res;
     }
};


Trapping Rain Water

Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining.

For example, 
Given [0,1,0,2,1,0,1,3,2,1,2,1], return 6.

The above elevation map is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped.

注意和上一题的区别,上一题相当于在每个位置放一个挡板,挡板之间可以蓄水;这一题是放置宽度为1的柱子,柱子上面可以蓄水。

 

算法4:分析某个柱子,发现该柱子上水的高度和其左右两边的最高柱子有关,设该柱子左边所有柱子中最高的为leftmax,右边所有柱子中最高的为rightmax,如果min(leftmax, rightmax) 大于该柱子的高度,那么该柱子上可以蓄水为min(leftmax, rightmax) - 该柱子高度,如果min(leftmax, rightmax) <= 该柱子高度,则该柱子上没有蓄水。

可以从后往前扫描一遍数组求得某个柱子右边的最高柱子,从前往后扫描一遍数组求得某个柱子左边的最高柱子, 然后按照上面的分析可以求得所有的蓄水量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class  Solution {
public :
     int  trap( int  A[], int  n) {
         int  res = 0;
         vector< int >rightMax(n); //柱子右边最大的柱子高度
         int  maxv = 0;
         for ( int  i = n-1; i >= 0; i--)
         {
             rightMax[i] = maxv;
             maxv < A[i] ? maxv = A[i] : maxv;
         }
         maxv = 0;
         int  conHeight;
         for ( int  i = 0; i < n; i++)
         { //此时maxv为柱子i左边最大的柱子高度
             conHeight = min(maxv, rightMax[i]);
             if (conHeight > A[i])
                 res += conHeight - A[i];
             maxv < A[i] ? maxv = A[i] : maxv;
         }
         return  res;
     }
};

上面的代码时间空间复杂度都是O(n),扫描了两次数组

 

算法5:可以换一种思路,如下图,如果我们求出了两个红色框的面积,然后再减去框内黑色柱子的面积,就是水的面积了,时间复杂度O(N),空间O(1), 数组扫描2次

image

如何求红色框内的面积呢,我们先求出最大的柱子高度,然后左右分开求。求面积是是一层一层的累加

image

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class  Solution {
public :
     int  trap( int  A[], int  n) {
         int  maxHeight = 0, maxIdx = 0;
         for ( int  i = 0; i < n; i++) //求最大高度
             if (A[i] > maxHeight)
             {
                 maxHeight = A[i];
                 maxIdx = i;
             }
         int  height = 0;
         int  pillarArea = 0; //柱子面积
         int  totalArea = 0; //总面积
         for ( int  i = 0; i < maxIdx; i++)
         {
             if (A[i] > height)
             {
                 totalArea += (A[i] - height)*(maxIdx - i);
                 height = A[i];
             }
             pillarArea += A[i];
         }
         height = 0;
         for ( int  i = n-1; i > maxIdx; i--)
         {
             if (A[i] > height)
             {
                 totalArea += (A[i] - height)*(i - maxIdx);
                 height = A[i];
             }
             pillarArea += A[i];
         }
         return  totalArea - pillarArea;
     }
};

 

算法6:参考here,也是和算法5一样求面积,但是这里利用上一题的左右指针思想,只需要扫描一遍数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class  Solution {
public :
     int  trap( int  A[], int  n) {
         int  left = 0, right = n-1;
         int  totalArea = 0, pillarArea = 0, height = 0;
         while (left <= right)
         {
             if (A[left] < A[right])
             {
                 if (A[left] > height)
                 {
                     totalArea += (A[left]-height)*(right - left + 1);
                     height = A[left];
                 }
                 pillarArea += A[left];
                 left++;
             }
             else
             {
                 if (A[right] > height)
                 {
                     totalArea += (A[right]-height)*(right - left + 1);
                     height = A[right];
                 }
                 pillarArea += A[right];
                 right--;
             }
         }
         return  totalArea - pillarArea;
     }
};

 






本文转自tenos博客园博客,原文链接:http://www.cnblogs.com/TenosDoIt/p/3812880.html,如需转载请自行联系原作者

目录
相关文章
|
人工智能 容器
Leetcode 11. Container With Most Water
题目可以这么理解,在i位置有条高为ai的竖线,让你选出两台竖线构成一个容器,使得该容器装的水最多,注意容器不能倾斜。
46 3
Leetcode 365. Water and Jug Problem
一句话理解题意:有容积为x和y升的俩水壶,能不能量出z升的水。 我刚开始看到这题,立马就想了下暴力搜索的可能性,但考虑了下数据大小,立马放弃这个暴力的想法,于是意识到肯定有比较简单的数学方法,其实我自己没想到,后来看还是看了别人的代码,很多博客都直接给出了解法, 但没介绍为什么能这么解。所以我决定解释下我自己的思路。
46 0
LeetCode 417. Pacific Atlantic Water Flow
给定一个 m x n 的非负整数矩阵来表示一片大陆上各个单元格的高度。“太平洋”处于大陆的左边界和上边界,而“大西洋”处于大陆的右边界和下边界。 规定水流只能按照上、下、左、右四个方向流动,且只能从高到低或者在同等高度上流动。 请找出那些水流既可以流动到“太平洋”,又能流动到“大西洋”的陆地单元的坐标。
109 0
LeetCode 417. Pacific Atlantic Water Flow
LeetCode 407. Trapping Rain Water II
我们把最外面的四边当成四面墙,想象海水面不断的升高,首先会浸过墙面最低的格子,如果墙面最低格子的四周(出了在墙面的格子)有比它矮的格子,那么这就可以形成一个蓄水池,蓄水池的最高高度就是墙面最低的格子,于是我们计算这个蓄水池可以获得的蓄水量;然后这个蓄水池被添加到墙面中;继续在墙面中找最低的格子;
96 0
LeetCode 407. Trapping Rain Water II
|
索引
LeetCode 42 Trapping Rain Water
给定n个非负整数,每个非负整数表示一个宽度为1的柱子,计算下雨后能够捕获多少水.
69 0
LeetCode 42 Trapping Rain Water
|
机器学习/深度学习 PHP 索引
[Leetcode 之 PHP 解析 (42. Trapping Rain Water)
[Leetcode 之 PHP 解析 (42. Trapping Rain Water)
106 0
[Leetcode 之 PHP 解析 (42. Trapping Rain Water)
|
容器
Leetcode-Medium 11. Container With Most Water
Leetcode-Medium 11. Container With Most Water
98 0
Leetcode-Medium 11. Container With Most Water
|
数据库
LeetCode(数据库)- The Airport With the Most Traffic
LeetCode(数据库)- The Airport With the Most Traffic
127 0
|
容器
LeetCode - 11. Container With Most Water
11. Container With Most Water  Problem's Link  ---------------------------------------------------------------------------- Mean:...
1008 0
|
2月前
|
Unix Shell Linux
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
本文提供了几个Linux shell脚本编程问题的解决方案,包括转置文件内容、统计词频、验证有效电话号码和提取文件的第十行,每个问题都给出了至少一种实现方法。
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行