盛水最多的容器
给定 n 个非负整数,其中每个代表坐标处的一个点。绘制 n 条垂直线,如下图所示:
找到两条线,它们与 x 轴一起形成一个容器,使得该容器包含最多的水。 该程序应返回一个整数,该整数对应于可容纳的最大水面积(最大面积而不是最大体积听起来很奇怪,但为了简单起见,这里我们使用 2D 平面)。
注意:容器不得倾斜。
例子 :
Input: array = [1, 5, 4, 3]
Output: 6
Explanation :
5 and 3 的横向距离是 2.
最小高度 = min(5, 3) = 3.
So total area = 3 * 2 = 6.
Input: array = [3, 1, 2, 4, 5]
Output: 12
Explanation :
5 and 3 的横向距离是 4.
最小高度 = min(5, 3) = 3.
So total area = 4 * 3 = 12
天真的解决方案:
- 方法:这个想法非常简单,检查每对边界,并找出任意对边界下的最大面积。
- 算法:
- 创建一个嵌套循环,外层循环从0到end遍历数组(本次循环的索引为i)。
- 内循环从i+1开始遍历数组到end(该循环的索引是j)。
- 求边界高度为 array[i] 和 array[j] 的容器中可容纳的水,即面积 = (j – i)* min(array[i],array[j]),如果面积大于当前最大值,更新当前最大值
- 打印当前最大值。
C++
// C++ code for Max
// Water Container
#include <iostream>
using namespace std;
int maxArea(int A[], int len)
{
int area = 0;
for (int i = 0; i < len; i++) {
for (int j = i + 1; j < len; j++) {
// Calculating the max area
area = max(area, min(A[j], A[i]) * (j - i));
}
}
return area;
}
// Driver code
int main()
{
int a[] = { 1, 5, 4, 3 };
int b[] = { 3, 1, 2, 4, 5 };
int len1 = sizeof(a) / sizeof(a[0]);
cout << maxArea(a, len1);
int len2 = sizeof(b) / sizeof(b[0]);
cout << endl << maxArea(b, len2);
}
Java
// Java code for Max
// Water Container
import java.io.*;
class GFG{
public static int maxArea(int[] a)
{
int Area = 0;
for(int i = 0; i < a.length; i++)
{
for(int j = i + 1; j < a.length; j++)
{
Area = Math.max(
Area, Math.min(a[i], a[j]) *
(j - i));
}
}
return Area;
}
// Driver code
public static void main(String[] args)
{
int a[] = { 1, 5, 4, 3 };
int b[] = { 3, 1, 2, 4, 5 };
System.out.println(maxArea(a));
System.out.println(maxArea(b));
}
}
Python
# Python3 code for Max
# Water Container
def maxArea(A, Len) :
area = 0
for i in range(Len) :
for j in range(i + 1, Len) :
# Calculating the max area
area = max(area, min(A[j], A[i]) * (j - i))
return area
# Driver code
a = [ 1, 5, 4, 3 ]
b = [ 3, 1, 2, 4, 5 ]
len1 = len(a)
print(maxArea(a, len1))
len2 = len(b)
print(maxArea(b, len2))
C#
// C# code for Max
// Water Container
using System;
class GFG
{
public static int maxArea(int[] a)
{
int Area = 0;
for(int i = 0; i < a.Length; i++)
{
for(int j = i + 1; j < a.Length; j++)
{
Area = Math.Max(Area, Math.Min(a[i], a[j]) *
(j - i));
}
}
return Area;
}
// Driver code
public static void Main(String[] args)
{
int []a = { 1, 5, 4, 3 };
int []b = { 3, 1, 2, 4, 5 };
Console.WriteLine(maxArea(a));
Console.Write(maxArea(b));
}
}
Javascript
<script>
// Javascript code for Max
// Water Container
function maxArea(A, len)
{
let area = 0;
for (let i = 0; i < len; i++) {
for (let j = i + 1; j < len; j++) {
// Calculating the max area
area = Math.max(area, Math.min(A[j], A[i]) * (j - i));
}
}
return area;
}
let a = [ 1, 5, 4, 3 ];
let b = [ 3, 1, 2, 4, 5 ];
let len1 = a.length;
document.write(maxArea(a, len1) + "</br>");
let len2 = b.length;
document.write(maxArea(b, len2));
</script>
输出:
6
12
复杂度分析:
- 时间复杂度:O(n^2)。 由于需要对数组进行嵌套遍历,所以时间复杂度为O(n^2)
- 空间复杂度:O(1)。 由于不需要额外的空间,因此空间复杂度是恒定的。
高效的解决方案:
- 保留两个索引,first = 0和last = n-1以及一个存储最大面积的值max_area。
- 运行循环,直到前索引first大于等于后索引last。
- 使用 max_area 和 min(array[first] , array[last])*(last-first) 中的最大值更新 max_area
- 如果array[first]的值大于array[last],则将last更新为last – 1,否则将first更新为first + 1
- 打印最大面积。
下面的 GIF 解释了该方法
C++
// C++ code for Max
// Water Container
#include<iostream>
using namespace std;
int maxArea(int A[], int len)
{
int l = 0;
int r = len -1;
int area = 0;
while (l < r)
{
// Calculating the max area
area = max(area, min(A[l],
A[r]) * (r - l));
if (A[l] < A[r])
l += 1;
else
r -= 1;
}
return area;
}
// Driver code
int main()
{
int a[] = {1, 5, 4, 3};
int b[] = {3, 1, 2, 4, 5};
int len1 = sizeof(a) / sizeof(a[0]);
cout << maxArea(a, len1);
int len2 = sizeof(b) / sizeof(b[0]);
cout << endl << maxArea(b, len2);
}
Java
// Java code for Max
// Water Container
import java.util.*;
class Area{
public static int maxArea(int A[], int len)
{
int l = 0;
int r = len -1;
int area = 0;
while (l < r)
{
// Calculating the max area
area = Math.max(area,
Math.min(A[l], A[r]) * (r - l));
if (A[l] < A[r])
l += 1;
else
r -= 1;
}
return area;
}
public static void main(String[] args)
{
int a[] = {1, 5, 4, 3};
int b[] = {3, 1, 2, 4, 5};
int len1 = 4;
System.out.print( maxArea(a, len1)+"\n" );
int len2 = 5;
System.out.print( maxArea(b, len2) );
}
}
Python
# Python3 code for Max
# Water Container
def maxArea( A):
l = 0
r = len(A) -1
area = 0
while l < r:
# Calculating the max area
area = max(area, min(A[l],
A[r]) * (r - l))
if A[l] < A[r]:
l += 1
else:
r -= 1
return area
# Driver code
a = [1, 5, 4, 3]
b = [3, 1, 2, 4, 5]
print(maxArea(a))
print(maxArea(b))
C#
// C# code for Max
// Water Container
using System;
class Area{
public static int maxArea(int []A, int len)
{
int l = 0;
int r = len -1;
int area = 0;
while (l < r)
{
// Calculating the max area
area = Math.Max(area,
Math.Min(A[l], A[r]) * (r - l));
if (A[l] < A[r])
l += 1;
else
r -= 1;
}
return area;
}
// Driver code
public static void Main()
{
int []a = {1, 5, 4, 3};
int []b = {3, 1, 2, 4, 5};
int len1 = 4;
Console.WriteLine( maxArea(a, len1));
int len2 = 5;
Console.WriteLine( maxArea(b, len2) );
}
}
PHP
<?php
// PHP code for Max
// Water Container
function maxArea($A, $len)
{
$l = 0;
$r = $len -1;
$area = 0;
while ($l < $r)
{
// Calculating the max area
$area = max($area, min($A[$l],
$A[$r]) * ($r - $l));
if ($A[$l] < $A[$r])
$l += 1;
else
$r -= 1;
}
return $area;
}
// Driver code
$a = array(1, 5, 4, 3);
$b = array(3, 1, 2, 4, 5);
$len1 = sizeof($a) / sizeof($a[0]);
echo maxArea($a, $len1). "\n";
$len2 = sizeof($b) / sizeof($b[0]);
echo maxArea($b, $len2);
?>
Javascript
<script>
// Javascript code for Max
// Water Container
function maxArea(A, len)
{
let l = 0;
let r = len -1;
let area = 0;
while (l < r)
{
// Calculating the max area
area = Math.max(area, Math.min(A[l],
A[r]) * (r - l));
if (A[l] < A[r])
l += 1;
else
r -= 1;
}
return area;
}
// Driver code
let a = [ 1, 5, 4, 3 ];
let b = [ 3, 1, 2, 4, 5 ];
let len1 = a.length;
document.write(maxArea(a, len1) + "</br>");
let len2 = b.length;
document.write(maxArea(b, len2));
</script>
输出
6
12
复杂度分析:
- 时间复杂度:O(n)。 由于只需要遍历一次数组,所以时间复杂度为O(n)。
- 空间复杂度:O(1)。 不需要额外的空间,因此空间复杂度是恒定的。
解决方案分析 – 为什么这个解决方案有效?
在每个状态下,无论长板或短板向中间收窄一格,都会导致水槽 底边宽度 −1 变短:
- 若向内 移动短板 ,水槽的短板 min(h[i],h[j]) 可能变大,因此下个水槽的面积 可能增大.
- 若向内 移动长板 ,水槽的短板 min(h[i],h[j]) 不变或变小,因此下个水槽的面积 一定变小.
- 因此,初始化双指针分列水槽左右两端,循环每轮将短板向内移动一格,并更新面积最大值,直到两指针相遇时跳出;即可获得最大面积.