C++实现LeetCode(42.收集雨水)

[LeetCode] 42. Trapping Rain Water 收集雨水

Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining.

The above elevation map is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped. Thanks Marcos for contributing this image!

Example:

Input: [0,1,0,2,1,0,1,3,2,1,2,1]
Output: 6

这道收集雨水的题跟之前的那道 Largest Rectangle in Histogram 有些类似,但是又不太一样,先来看一种方法,这种方法是基于动态规划 Dynamic Programming 的,维护一个一维的 dp 数组,这个 DP 算法需要遍历两遍数组,第一遍在 dp[i] 中存入i位置左边的最大值,然后开始第二遍遍历数组,第二次遍历时找右边最大值,然后和左边最大值比较取其中的较小值,然后跟当前值 A[i] 相比,如果大于当前值,则将差值存入结果,参见代码如下:

C++ 解法一:

class Solution {
public:
    int trap(vector<int>& height) {
        int res = 0, mx = 0, n = height.size();
        vector<int> dp(n, 0);
        for (int i = 0; i < n; ++i) {
            dp[i] = mx;
            mx = max(mx, height[i]);
        }
        mx = 0;
        for (int i = n - 1; i >= 0; --i) {
            dp[i] = min(dp[i], mx);
            mx = max(mx, height[i]);
            if (dp[i] > height[i]) res += dp[i] - height[i];
        }
        return res;
    }
};

Java 解法一:

public class Solution {
    public int trap(int[] height) {
        int res = 0, mx = 0, n = height.length;
        int[] dp = new int[n];
        for (int i = 0; i < n; ++i) {
            dp[i] = mx;
            mx = Math.max(mx, height[i]);
        }
        mx = 0;
        for (int i = n - 1; i >= 0; --i) {
            dp[i] = Math.min(dp[i], mx);
            mx = Math.max(mx, height[i]);
            if (dp[i] - height[i] > 0) res += dp[i] - height[i];
        }
        return res;
    }
}

再看一种只需要遍历一次即可的解法,这个算法需要 left 和 right 两个指针分别指向数组的首尾位置,从两边向中间扫描,在当前两指针确定的范围内,先比较两头找出较小值,如果较小值是 left 指向的值,则从左向右扫描,如果较小值是 right 指向的值,则从右向左扫描,若遇到的值比当较小值小,则将差值存入结果,如遇到的值大,则重新确定新的窗口范围,以此类推直至 left 和 right 指针重合,参见代码如下:

C++ 解法二:

class Solution {
public:
    int trap(vector<int>& height) {
        int res = 0, l = 0, r = height.size() - 1;
        while (l < r) {
            int mn = min(height[l], height[r]);
            if (mn == height[l]) {
                ++l;
                while (l < r && height[l] < mn) {
                    res += mn - height[l++];
                }
            } else {
                --r;
                while (l < r && height[r] < mn) {
                    res += mn - height[r--];
                }
            }
        }
        return res;
    }
};

Java 解法二:

public class Solution {
    public int trap(int[] height) {
        int res = 0, l = 0, r = height.length - 1;
        while (l < r) {
            int mn = Math.min(height[l], height[r]);
            if (height[l] == mn) {
                ++l;
                while (l < r && height[l] < mn) {
                    res += mn - height[l++];
                }
            } else {
                --r;
                while (l < r && height[r] < mn) {
                    res += mn - height[r--];
                }
            }
        }
        return res;
    }
}

我们可以对上面的解法进行进一步优化,使其更加简洁:

C++ 解法三:

class Solution {
public:
    int trap(vector<int>& height) {
        int l = 0, r = height.size() - 1, level = 0, res = 0;
        while (l < r) {
            int lower = height[(height[l] < height[r]) ? l++ : r--];
            level = max(level, lower);
            res += level - lower;
        }
        return res;
    }
};

Java 解法三:

public class Solution {
    public int trap(int[] height) {
        int l = 0, r = height.length - 1, level = 0, res = 0;
        while (l < r) {
            int lower = height[(height[l] < height[r]) ? l++ : r--];
            level = Math.max(level, lower);
            res += level - lower;
        }
        return res;
    }
}

下面这种解法是用 stack 来做的,博主一开始都没有注意到这道题的 tag 还有 stack,所以以后在总结的时候还是要多多留意一下标签啊。其实用 stack 的方法博主感觉更容易理解,思路是,遍历高度,如果此时栈为空,或者当前高度小于等于栈顶高度,则把当前高度的坐标压入栈,注意这里不直接把高度压入栈,而是把坐标压入栈,这样方便在后来算水平距离。当遇到比栈顶高度大的时候,就说明有可能会有坑存在,可以装雨水。此时栈里至少有一个高度,如果只有一个的话,那么不能形成坑,直接跳过,如果多余一个的话,那么此时把栈顶元素取出来当作坑,新的栈顶元素就是左边界,当前高度是右边界,只要取二者较小的,减去坑的高度,长度就是右边界坐标减去左边界坐标再减1,二者相乘就是盛水量啦,参见代码如下:

C++ 解法四:

class Solution {
public:
    int trap(vector<int>& height) {
        stack<int> st;
        int i = 0, res = 0, n = height.size();
        while (i < n) {
            if (st.empty() || height[i] <= height[st.top()]) {
                st.push(i++);
            } else {
                int t = st.top(); st.pop();
                if (st.empty()) continue;
                res += (min(height[i], height[st.top()]) - height[t]) * (i - st.top() - 1);
            }
        }
        return res;
    }
};

Java 解法四:

class Solution {
    public int trap(int[] height) {
        Stack<Integer> s = new Stack<Integer>();
        int i = 0, n = height.length, res = 0;
        while (i < n) {
            if (s.isEmpty() || height[i] <= height[s.peek()]) {
                s.push(i++);
            } else {
                int t = s.pop();
                if (s.isEmpty()) continue;
                res += (Math.min(height[i], height[s.peek()]) - height[t]) * (i - s.peek() - 1);
            }
        }
        return res;
    }
}

到此这篇关于C++实现LeetCode(42.收集雨水)的文章就介绍到这了,更多相关C++实现收集雨水内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++实现LeetCode(44.外卡匹配)

    [LeetCode] 44. Wildcard Matching 外卡匹配 Given an input string (s) and a pattern (p), implement wildcard pattern matching with support for '?' and '*'. '?' Matches any single character. '*' Matches any sequence of characters (including the empty sequenc

  • C++实现LeetCode(8.字符串转为整数)

    [LeetCode] 8. String to Integer (atoi) 字符串转为整数 Implement atoi which converts a string to an integer. The function first discards as many whitespace characters as necessary until the first non-whitespace character is found. Then, starting from this ch

  • C++实现LeetCode(验证数字)

    [LeetCode] Valid Number 验证数字 Validate if a given string can be interpreted as a decimal number. Some examples: "0" => true " 0.1 " => true "abc" => false "1 a" => false "2e10" => true "

  • C++实现LeetCode(10.正则表达式匹配)

    [LeetCode] 10. Regular Expression Matching 正则表达式匹配 Given an input string (s) and a pattern (p), implement regular expression matching with support for '.' and '*'. '.' Matches any single character. '*' Matches zero or more of the preceding element. T

  • C++实现LeetCode(7.翻转整数)

    [LeetCode] 7. Reverse Integer 翻转整数 Given a 32-bit signed integer, reverse digits of an integer. Example 1: Input: 123 Output: 321 Example 2: Input: -123 Output: -321 Example 3: Input: 120 Output: 21 Note: Assume we are dealing with an environment whi

  • C++实现LeetCode(11.装最多水的容器)

    [LeetCode] 11. Container With Most Water 装最多水的容器 Given n non-negative integers a1, a2, ..., an , where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two

  • C++实现LeetCode(132.拆分回文串之二)

    [LeetCode] 132.Palindrome Partitioning II 拆分回文串之二 Given a string s, partition s such that every substring of the partition is a palindrome. Return the minimum cuts needed for a palindrome partitioning of s. Example: Input: "aab" Output: 1 Explan

  • C++实现LeetCode(647.回文子字符串)

    [LeetCode] 647. Palindromic Substrings 回文子字符串 Given a string, your task is to count how many palindromic substrings in this string. The substrings with different start indexes or end indexes are counted as different substrings even they consist of sa

  • C++实现LeetCode(6.字型转换字符串)

    [LeetCode] 6. ZigZag Conversion 之字型转换字符串 The string "PAYPALISHIRING" is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility) P   A   H   N A P L S I I G Y  

  • C++实现LeetCode(42.收集雨水)

    [LeetCode] 42. Trapping Rain Water 收集雨水 Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining. The above elevation map is represented by array [0,1,0,2,1,

  • LeetCode -- Path Sum III分析及实现方法

    LeetCode -- Path Sum III分析及实现方法 题目描述: You are given a binary tree in which each node contains an integer value. Find the number of paths that sum to a given value. The path does not need to start or end at the root or a leaf, but it must go downwards

  • 收集的48个Shell脚本小技巧

    本文收集了一堆的shell脚本技巧,我说过,我写博客主要是作一些学习笔记,方便自己查阅,所以,我会搞出这么一篇文章,也没有什么不可理解的.关于这些技巧的出处,诶,我也忘了,可能来自theunixschool. commandlinefu.酷勤网和igigo.net,当然了,也有部分是我自己的经验心得,管他呢,进了我的脑子就是我的了. 0. shell 调试 复制代码 代码如下: sh -x somefile.sh 在somefile.sh 文件里加上set+x set-x 1. 用 &&

  • 收集的数千软件序列号

    Windows XP Professional CD w/SP2 简体中文专业版*-华军软件商城价格: 1550.00 元/套 正版序列号:HH7VV-6P3G9-82TWK-QKJJ3-MXR96 正版序列号:F4297-RCWJP-P482C-YY23Y-XH8W3 正版序列号:MRX3F-47B9T-2487J-KWKMF-RPWBY 正版序列号:QC986-27D34-6M3TY-JJXP9-TBGMD office 2003 中文专业版*-华军软件商城价格: 3250.00 元/套 正

  • 收集的二十一个实用便利的PHP函数代码

    PHP 是目前使用最广泛的基于 Web 的编程语言,驱动着数以百万计的网站,其中也包括如 Facebook 等一些大型站点.这里收集了 21 段实用便捷的 PHP 代码摘录,对每种类型的 PHP 开发者都会有所帮助. 1. PHP可阅读随机字符串 此代码将创建一个可阅读的字符串,使其更接近词典中的单词,实用且具有密码验证功能. /***************@length - length of random string (must be a multiple of 2)**********

  • 60个很实用的jQuery代码开发技巧收集

    由于内容比较多建议用CTRL+F搜索 偶然在网上看到这些不错的jQuery代码开发技巧.原文收集了30个,另外查找的时候发现了还有20个.加上另外十个实用的jQuery代码片段,共60个代码技巧,收集在一起分享给大家. 1. 创建一个嵌套的过滤器 .filter(":not(:has(.selected))") //去掉所有不包含class为.selected的元素 2. 重用你的元素查询 var allItems = $("div.item"); var keep

  • linux下定时执行任务的方法及crontab 用法说明(收集整理)

    linux下定时执行任务的方法 在LINUX中,周期执行的任务一般由cron这个守护进程来处理[ps -ef|grep cron].cron读取一个或多个配置文件,这些配置文件中包含了命令行及其调用时间. cron的配置文件称为"crontab",是"cron table"的简写. 一.cron在3个地方查找配置文件: 1./var/spool/cron/ 这个目录下存放的是每个用户包括root的crontab任务,每个任务以创建者的名字命名,比如tom建的cron

  • PHP 实用代码收集

    1. 可阅读随机字符串 此代码将创建一个可阅读的字符串,使其更接近词典中的单词,实用且具有密码验证功能. 复制代码 代码如下: /************** *@length - length of random string (must be a multiple of 2) **************/ function readable_random_string($length = 6){ $conso=array("b","c","d&quo

  • SpringBoot使用Graylog日志收集的实现示例

    本文介绍SpringBoot如何使用Graylog日志收集. 1.Graylog介绍 Graylog是一个生产级别的日志收集系统,集成Mongo和Elasticsearch进行日志收集.其中Mongo用于存储Graylog的元数据信息和配置信息,ElasticSearch用于存储数据. 架构图如下: 生产环境配置图如下: 2.安装Graylog 在官方文档上推荐了很多种安装的方式,这里以docker-compose的方式为例,进行安装Graylog,mongo,elasticsearch. do

随机推荐