原文链接:go leetcode,php 代码个人原创
盛最多水的容器(Container-With-Most-Water)
题干如下:
给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。 说明:你不能倾斜容器,且 n 的值至少为 2。 图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。 示例: 输入:[1,8,6,2,5,4,8,3,7] 输出:49 来源:力扣
根据题意,将题目抽象为数学模型:给定一个 数组array 和 两个索引X、Y,在随意移动 X、Y 的过程中,求 **S = | Y-X | * Min( array[X], array[Y] )** 的最大值,其中 Min( array[X], array[Y] ) 记为 H。 |
>1. | Y-X | 表示索引差值的绝对值 |
2. Min( array[X], array[Y] ) ,是因为在 | Y-X | 固定的前提下,容器的纳水量完全取决于较小的高度,所以这边取 Min。 |
解题思路
我们将 X 指向数组的第一个位置,Y 指向数组的最后一个位置。按照上面的公式求出 S 的值并记录。判断 array[X] 和 array[Y] 的值,如果 array[X] > array[Y] 则 Y 向左移动,如果 array[X] < array[Y] 则 X 向右移动,如果 array[X] = array[Y] 则 X 向右移动,Y 向左移动。总之,索引指向的元素值较小的移动,如果相等则一起移动。解释如下:
假设 X 指向的元素为 2,Y 指向的元素为 7。由于 2 比 7 小,所以 X 向右移。至于为什么不是 Y 向左移动是因为 H的值 是 array[X] 和 array[Y] 中较小的值,如果将 Y 向左移动,假设 array[Y-1] 比 array[X] 大,这时 H的值 仍为 array[X],而(Y - X)的值却变小了,因此 S 也变小了。假设 array[Y-1] 比 array[X] 小,这时 H的值 为 array[Y-1] ,较之前变小了,并且 (Y - X)的值也变小了,因此 S 也变小了。所以要移动元素值较小的索引。如果 array[X] 和 array[Y] 相等,则 X 和 Y 一起移动,分析过程与不相等一致。
流程图分析如下:
Go 实现:
func maxArea(height []int) int {
var (
i = 0
j = len(height) - 1
max = 0
minHeight = 0
)
for i < j {
// H 的 计算
if height[j] > height[i] {
minHeight = height[i]
} else {
minHeight = height[j]
}
// 记录面积,也就是纳水量
newMax := (j - i) * minHeight
if newMax > max {
max = newMax
}
// 移动高度小的指针,如果相等则一起移动
if height[j] > height[i] {
i++
} else if height[j] < height[i] {
j--
} else {
j--
i++
}
}
return max
}
PHP 实现:
function maxArea($nums) {
$i = 0;
$j = count($nums) - 1;
$max = 0;
while ($i < $j) {
if ($nums[$j] > $nums[$i]) {
$minHeight = $nums[$i];
} else {
$minHeight = $nums[$j];
}
// 记录面积
$newMax = ($j - $i) * $minHeight;
if ($newMax > $max) {
$max = $newMax;
}
// 移动高度小的指针,如果相等则一起移动
if ($nums[$j] > $nums[$i]) {
$i++;
} elseif ($nums[$j] < $nums[$i]) {
$j--;
} else {
$j--;
$i++;
}
}
return $max;
}
echo maxArea([1,8,6,2,5,4,8,3,7]); // output: 49
PHP 实现2 - 来自 laravel china 社区 Littlesqx
function maxArea($nums) {
$max = $start = 0;
$end = count($nums) - 1;
while ($start <= $end) {
$max = max($max, min($nums[$start], $nums[$end]) * ($end - $start));
$nums[$start] > $nums[$end] ? $end-- : $start++;
}
return $max;
}
echo maxArea([1,8,6,2,5,4,8,3,7]); // output: 49
最后恰饭 阿里云全系列产品/短信包特惠购买 中小企业上云最佳选择 阿里云内部优惠券