「这是我参与11月更文挑战的7天,活动详情查看:2021最后一次更文挑战」。
前言
一直都计划学习数据结构与基本算法,但是平时都看一阵停一阵。现在决心坚持下去,我准备从LeetCode的HOT100开始,每天完成1~2道习题,希望通过这种方式养成持续学习的习惯。因为我是做iOS开发的,主要是用Objective-C语言,最近也在学习Swift,所以本系列的题解都将使用swift语言完成,本文更新的是LeetCode中HOT100的第7题011盛最多水的容器。
题目
给你 n 个非负整数,每个数代表坐标中的一个点 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 和 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:你不能倾斜容器。
示例 1:
输入:[1,8,6,2,5,4,8,3,7]
输出:49
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
示例 2:
输入:height = [1,1]
输出:1
示例 3:
输入:height = [4,3,2,1,4]
输出:16
示例 4:
输入:height = [1,2,1]
输出:2
提示:
n == height.length
2 <= n <= 105
0 <= height[i] <= 104
分析
本题的意思类似我们常见的木桶原理,一个木桶所能装水的多少取决于最短的那根木板。本题中两个元素和之间所能盛的水的多少为 。本题是要求所有中的最大值。
显然,最常见的方法是暴力法(枚举法),一次求出每一个的值,然后获取最大值进行返回,该方法对应的复杂度应该是 O(n2)。该方法的解题思路类似冒泡法,就是一个双重循环,就不细说了。
本题的题解采用双指针法,是对上述的暴力解法的改进版本。基本思路是设两指针 ,指向的水槽板高度分别为 ,此状态下水槽面积为 。由于可容纳水的高度由两板中的 短板 决定,因此可得如下 面积公式 :。
在每个状态下,无论长板或短板向中间收窄一格,都会导致水槽 底边宽度 −1, 变短:
- 若向内 移动短板 ,水槽的短板 可能变大,因此下个水槽的面积 可能增大 。
- 若向内 移动长板 ,水槽的短板 不变或变小,因此下个水槽的面积 一定变小 。 因此,初始化双指针分列水槽左右两端,循环每轮将短板向内移动一格,并更新面积最大值,直到两指针相遇时跳出;即可获得最大面积。
双指针法的基本流程如下:
1、初始化:设定双指针 left , right 初始值分别指向水槽左右两端的下标;设定maxArea初始值为0,表示当前最大容量
2、计算当前值:计算当前有left、right下标对应的元素组成的容器的的容量,S(left,right) = min(h[left],h[right]) × (right − left),并更新maxArea为当前最大值
3、指针移动:将当前left、right对应的较小值,向内移动到比原先值大的新值(如果h[left] <= h[right],则将left向右移动,直到新的left对应的值大于原先left对应的值,如果h[left] < h[right],则将right向左移动,直到新的right对应的值大于原先right对应的值)
4、循环:重复步骤2~步骤4,直至left >= right
该方法的复杂度为 O(n),相对暴力解法更简单。
题解
class KLLC011 {
func maxArea(_ height: [Int]) -> Int {
//初始化
var left = 0, right = height.count - 1
var maxArea = 0
//循环结束条件为left >= right,则循环继续的提交为left < right
while left < right {
//计算当前left right组成的容积
let curH = min(height[left], height[right])
let curArea = curH * (right - left)
//更新maxArea
if maxArea < curArea {
maxArea = curArea
}
//根据left right对应值的大小进行向内移动
if height[left] <= height[right] {
//h[left] <= h[right],则将left向右移动,直到新的left对应的值大于原先left对应的值
repeat {
left += 1
} while left < right && curH >= height[left]
} else {
//h[left] < h[right],则将right向左移动,直到新的right对应的值大于原先right对应的值
repeat {
right -= 1
} while left < right && curH >= height[right]
}
}
//返回最大容积
return maxArea
}
}