给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 感谢 Marcos 贡献此图。

示例:

输入: [0,1,0,2,1,0,1,3,2,1,2,1]

输出: 6

分析:

解法1:暴力法

对每个元素取其左右两边的最大值的最小值,然后减去当前值

时间复杂度:O(N^2),对每个元素都需要取其左右两边的最大值

空间复杂度:O(1)

class Solution
{
public:
int trap(vector<int>& v)
{
int ans=0;
if(v.size()==0)
return 0;
for(int i=1; i<v.size()-1; i++)
{
int leftmax=0;
for(int j1=i-1; j1>=0; j1--) //取其左边元素的最大值
{
leftmax=max(leftmax,v[j1]);
}
int rightmax=0;
for(int j2=i+1; j2<v.size(); j2++) //取其右边元素的最大值
{
rightmax=max(rightmax,v[j2]);
}
int x=min(leftmax,rightmax)-v[i];//取两个最大值的最小值
if(x>0)//能够储水
{
ans+=x;//符合要求则加上
}
}
return ans;
}
}

解法2:动态规划

暴力法每次都有寻找其左右两边最大元素的最小值

我们可以通过两次O(N)的遍历记录下当前元素的左右两边最大值的最小值

时间复杂度:O(N)

空间复杂度:O(N)

class Solution
{
public:
int trap(vector<int>& v)
{
int ans=0;
if(v.size()==0)
return 0;
int n=v.size();
int dp[n];//dp[i]:当前元素i左右两边最大值的最小值
dp[0]=0;
dp[n-1]=0; for(int i=1; i<n-1; i++) //左边最大值
{
dp[i]=max(dp[i-1],v[i-1]);
}
for(int i=n-2; i>=1; i--) //右边最大值和当前左边最小值比较
{
dp[i]=min(dp[i],max(dp[i+1],v[i+1]));
}
for(int i=1; i<n-1; i++) //符合要求累加即可
{
if(dp[i]-v[i]>0)
ans+=dp[i]-v[i];
}
return ans;
}
}

解法3:左右双指针法



先找到最高点k,k把数组分为了左右两部分

对左半部分的当前值来说:

如果当前值大于当前值左边的最大值,那么水就会向左边流走,当前值就储存不了水,只能更新一下左边最大值

如果当前值不大于当前值左边的最大值,那么就可以储存住水,水的量就是当前左边最大值减去当前值

对右半部分的当前值来说:

如果当前值小于当前值右边的最大值,那么水就会向右边流走,当前值就储存不了水,只能更新一下右边最大值

如果当前值不大于当前值右边的最大值,那么就可以储存住水,水的量就是当前右边最大值减去当前值

注意,左边最大值和右边最大值都不是相对于整个左边部分或右边部分来说的

左边最大值是相当于当前元素的左边的所有元素来说的

右边最大值是相当于当前元素的右边的所有元素来说的

时间复杂度:O(N)

空间复杂度:O(1)

class Solution
{
public:
int trap(vector<int>& v)
{
int ans=0;
int n=v.size();
if(n==0)
return 0;
int k=0;
for(int i=1; i<n; i++) //找到最高点k,k把数组分为左右两部分(都不包含k)
{
if(v[i]>v[k])
k=i;
}
int maxleft=0;//左边最大值指针
for(int i=1; i<k; i++) //左半部分
{
if(v[maxleft]<v[i])//不能储水,水向左边流走了
maxleft=i;//更新左边最大值
else
ans+=(v[maxleft]-v[i]);//可以储存水
}
int maxright=n-1;//右边最大值指针
for(int i=n-2; i>k; i--) //右半部分
{
if(v[maxright]<v[i])//不能储存水。水向右边流走了
maxright=i;//更新右边最大值
else
ans+=(v[maxright]-v[i]);//可以储存水
}
return ans;
}
}

【leet-code】接雨水的更多相关文章

  1. 【Leet Code】Palindrome Number

    Palindrome Number Total Accepted: 19369 Total Submissions: 66673My Submissions Determine whether an ...

  2. Leet Code 771.宝石与石头

    Leet Code编程题 希望能从现在开始,有空就做一些题,自己的编程能力太差了. 771 宝石与石头 简单题 应该用集合来做 给定字符串J 代表石头中宝石的类型,和字符串 S代表你拥有的石头. S  ...

  3. #Leet Code# Gray Code

    描述: 要求相邻数2进制差一位 先获得n-1的列表表示小于 2^(n-1) 的符合要求的列表,加上最高位的加成 2^(n-1) 就是大于等于 2^(n-1) 的符合要求的列表,后者翻转一下就能够与前者 ...

  4. #Leet Code# Permutation

    描述: 输出全排列 代码: class Solution: # @param num, a list of integer # @return a list of lists of integers ...

  5. #Leet Code# Unique Path(todo)

    描述: 使用了递归,有些计算是重复的,用了额外的空间,Version 1是m*n Bonus:一共走了m+n步,例如 m = 2, n = 3 [#, @, @, #, @],所以抽象成数学问题,解是 ...

  6. #Leet Code# Populating Next Right Pointers in Each Node II

    描述:注意需要先self.connect(right)再self.connect(left),否则会有case通不过,原因是左边递归执行时依赖与右边的next已经建立,而先执行connect(left ...

  7. #Leet Code# Sqrt

    描述:log(n) 代码: class Solution: # @param x, an integer # @return an integer def getVal(self, begin, en ...

  8. #Leet Code# Best Time to Buy and Sell Stock

    描述:数组 A,对于 i < j, 找到最大的 A[j] - A[i] 代码: class Solution: # @param prices, a list of integer # @ret ...

  9. #Leet Code# Convert Sorted Array to Binary Search Tree

    描述:递归 代码: class Solution: # @param num, a list of integers # @return a tree node def sortedArrayToBS ...

  10. #Leet Code# Evaluate Reverse Polish Notation

    描述:计算逆波兰表达法的结果 Sample: [", "*"] -> ((2 + 1) * 3) -> 9 [", "/", & ...

随机推荐

  1. 初阶sql注入总结

    0x00 前言 sql注入是通过用户输入构造语句以实现目的.一句话,不要相信任何用户输入的内容,做好防护. 0x01 传参方式 传参方式一般通过get方式,或者post方式提交,前者的优点是效率高,后 ...

  2. python中的 dict() 函数

    Python 字典 dict() 函数用于创建一个新的字典,用法与 Pyhon 字典 update() 方法相似. dict() 函数函数语法: dict(key/value) 参数说明: key/v ...

  3. k8s集群搭建(一)

    k8s简介 kubernetes,简称K8s,是用8代替8个字符“ubernete”而成的缩写.是一个开源的,用于管理云平台中多个主机上的容器化的应用,Kubernetes的目标是让部署容器化的应用简 ...

  4. 【Tomcat】使用Eclipse绑定Tomcat 发布应用&&常见错误

     创建时间:6.14 一.Eclipse绑定Tomcat 步骤1:获得服务器运行环境配置,Window/Preferences/Server/Runtime Environment 步骤2:添加服务器 ...

  5. python基础语法17 面向对象4 多态,抽象类,鸭子类型,绑定方法classmethod与staticmethod,isinstance与issubclass,反射

    多态 1.什么是多态? 多态指的是同一种类型的事物,不同的形态. 2.多态的目的: “多态” 也称之为 “多态性”,目的是为了 在不知道对象具体类型的情况下,统一对象调用方法的规范(比如:名字). 多 ...

  6. 21-C#笔记-名称空间

    和C++不同的地方: 1. 访问内部成员的方式使用 点 namespace_name.item_name; 2. using 的语法 using System; 参考: http://www.runo ...

  7. USACO Superprime Rib

    洛谷 P1218 [USACO1.5]特殊的质数肋骨 Superprime Rib 洛谷传送门 JDOJ 1673: Superprime Rib JDOJ传送门 题目描述 农民约翰的母牛总是产生最好 ...

  8. Comet OJ 夏季欢乐赛 完全k叉树

    完全k叉树 https://cometoj.com/contest/59/problem/A?problem_id=2712 题目描述 欢迎报考JWJU!这里有丰富的社团活动,比如为梦想奋斗的ACM集 ...

  9. python--协程知识初识

    线程和进程的操作是由程序触发系统接口,最后的执行者是系统:协程的操作则是程序员. 协程存在的意义:对于多线程应用,CPU通过切片的方式来切换线程间的执行,线程切换时需要耗时(保存状态,下次继续).协程 ...

  10. opengl第一个工程

    #include <iostream> #include <glad/glad.h> #include <GLFW/glfw3.h> void framebuffe ...