这是我参与11月更文挑战的20天,活动详情查看:2021最后一次更文挑战。
前言
一直都计划学习数据结构与基本算法,但是平时都看一阵停一阵。现在决心坚持下去,我准备从LeetCode的HOT100开始,每天完成1~2道习题,希望通过这种方式养成持续学习的习惯。因为我是做iOS开发的,主要是用Objective-C语言,最近也在学习Swift,所以本系列的题解都将使用swift语言完成,本文更新的是LeetCode中HOT100的第20题042 接雨水。
题目
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例 1:
输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。
复制代码
示例 2:
输入:height = [4,2,0,3,2,5]
输出:9
复制代码
提示:
n == height.length
1 <= n <= 2 * 104
0 <= height[i] <= 105
复制代码
分析
在本题中,我们需要计算每一列中可以装水的容量,但是每一列可以装水的容量又取决有其左边和右边的墙的高度,对第 i 列,其可以装水的容量与其左右两边墙的高度的的关系如下图所示。 对于第 i 列,其装水容量只与左右两侧的最高墙有关,具体关系是 。所以我们可以用两个数组来保存对于每一列,其左侧和右侧的最高墙的高度,然后计算每一列装水容量。具体思路如下:
1. 初始化数组leftMaxList、rightMaxList用来保存每一列对应的左侧和右侧最高墙的高度
2. 从左往右遍历height数组,将当前第 i 列左侧(包括当前列)最大值保存到leftMaxList[i]
3. 从右往左遍历height数组,将当前第 i 列右侧(包括当前列)最大值保存到rightMaxList[i]
4. 从左往右遍历height数组,根据第 i 列的容量计算公式 area_i = min(leftMax, rightMax) - height[i] 计算每一列的容量,并进行求和
复制代码
题解
class Solution {
// 动态规划
// 时间O(n) 共访问3次 一次左边 一次右边 一次计算
// 空间O(n)
func trap(_ height: [Int]) -> Int {
// write code here
var leftMax = 0
// 每个位置左边的最高值 最低值为当前位置的值
var leftMaxList: [Int] = []
for n in height {
leftMax = max(leftMax, n)
leftMaxList.append(leftMax)
}
var rightMax = 0
// 每个位置右边的最高值 最低值为当前位置的值
var rightMaxList: [Int] = []
for n in height.reversed() {
rightMax = max(rightMax, n)
rightMaxList.insert(rightMax, at: 0)
}
//计算总容量
var sum = 0
for (index, n) in height.enumerated() {
let n1 = leftMaxList[index]
let n2 = rightMaxList[index]
// 当前位置的容量 = 左右最高值中的低值 (低值最为当前位置的值) - 当前位置的值
sum += (min(n1, n2) - n)
}
return sum
}
}
复制代码