菜鸡每日一题系列打卡42天
每天一道算法题目
小伙伴们一起留言打卡
坚持就是胜利,我们一起努力!
题目描述(引自LeetCode)
给定n个非负整数表示每个宽度为1的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
上面是由数组[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
题目分析
这道题目的数学模型是数组,而求解的过程是对木桶原理的应用。
最朴素的想法是暴力法。针对每一个数组的值,遍历数组以获得当前位置对雨水的贡献量,这种方式的时间复杂度为O(n^2),空间复杂度为O(1)。
进一步考虑,可以采用动态规划的解法。先对数组进行一次从左到右的遍历和一次从右到左的遍历,并用两个数组记录针对当前位置的左侧最大值和右侧最大值,然后再进行计算,这种方式将时间复杂度优化为O(n),但使用了额外的数组空间,空间复杂度为O(n)。
更进一步考虑,可以使用双指针的方式实现。其实并不需要使用额外的数组空间对当前的左侧最大值和右侧最大值进行存储,只需要使用双指针记录即可,使用双指针记录不仅可以节约空间,而且也不需要提前对数组进行两次遍历,仅在一次遍历中就可以完成对结果的计算,也节约了时间。
其实,对常规的数组类型的题目,无非就是暴力求解,动态规划,双指针等常用的方式进行解决。本文采用双指针的方式进行实现,对本题而言,该方式的时间和空间方面的综合表现最优。
代码实现
class Solution {
public int trap(int[] height) {
// 特殊情况判断
if (height == null || height.length < 3) return 0;
// 结果变量
int result = 0;
// 双指针
int start = 0, end = height.length - 1;
// 在双指针扫描过程中,实时更新两侧的最大值
int startMax = height[start], endMax = height[end];
// 扫描,以木桶原理为依据更新结果
while (start < end) {
if (height[start] < height[end]) {
if (height[start] > startMax) startMax = height[start];
else if (height[start] < startMax) result += startMax - height[start];
start++;
} else {
if (height[end] > endMax) endMax = height[end];
else if (height[end] < endMax) result += endMax - height[end];
end--;
}
}
// 返回结果
return result;
}
}
代码分析
对代码进行分析,算法仅仅对输入数组进行了一次扫描,因此,时间复杂度为O(n),而就空间而言,仅仅使用了常数级别的额外空间,因此,空间复杂度为O(1)。
执行结果
其他说明
由于微信公众号的页面模板功能的限制,一个页面模板仅支持保存30篇文章,由于每日一题系列更新已经超过了30篇,因此,菜鸡将其全部归类到每日一题专辑中,在每日一题栏目中仅保存最近更新的30篇,需要翻看历史文章的,可以点击文章顶部的专辑进行查看,其余栏目也可采用该方式查看。如下图所示????。
学习 | 工作 | 分享
????长按关注“有理想的菜鸡”
只有你想不到,没有你学不到