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

 更新时间:2021年07月12日 14:12:58   作者:Grandyang  
这篇文章主要介绍了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++实现收集雨水内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C++基础入门教程(二):数据、变量、宏等

    C++基础入门教程(二):数据、变量、宏等

    这篇文章主要介绍了C++基础入门教程(二):数据、变量、宏等,本文讲解了变量初始化、宏定义、三种进制数的表示、const初探、auto声明等内容,需要的朋友可以参考下
    2014-11-11
  • C语言 深入理解动态规划之计数类DP

    C语言 深入理解动态规划之计数类DP

    动态规划可谓是大名鼎鼎,笔试面试中的高频考点,也是重点难点,动态规划类型题目灵活多变,难度系数也相对较高,往往我们做不好动态规划的题目就会与心仪的offer失之交臂,本篇文章我们就一起来研究一下动态规划的计数类DP
    2022-04-04
  • 浅谈C++模板元编程

    浅谈C++模板元编程

    本篇文章主要介绍了浅谈C++模板元编程,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-12-12
  • C++面向对象实现万年历的示例代码

    C++面向对象实现万年历的示例代码

    本文将通过面向对象实现一个简单的日历(万年历)效果,主要会有以下几个模块:模型、视图、控制,感兴趣的小伙伴可以动手尝试一下
    2022-06-06
  • c++ 递归锁的使用示例代码

    c++ 递归锁的使用示例代码

    这篇文章主要介绍了c++ 递归锁的使用示例代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-08-08
  • C++中auto类型说明符详解(附易错实例)

    C++中auto类型说明符详解(附易错实例)

    这篇文章主要给大家介绍了关于C++中auto类型说明符的相关资料,文中还附易错实例,在C++11中引入了auto类型说明符,用它就能让编译器替我们去分析表达式所属的类型,需要的朋友可以参考下
    2023-07-07
  • C++结合QT实现带有优先级的计算器功能

    C++结合QT实现带有优先级的计算器功能

    这篇文章主要介绍了C++结合QT实现带有优先级的计算器,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-01-01
  • C++解析ini文件的实现方法

    C++解析ini文件的实现方法

    在C++编程中,有时我们需要处理配置文件来存储应用程序的设置和参数,而INI文件是一种常见的选择,这篇文章主要给大家介绍了关于C++解析ini文件的实现方法,需要的朋友可以参考下
    2024-08-08
  • C++报错`Null Pointer Dereference`的解决方法

    C++报错`Null Pointer Dereference`的解决方法

    在软件开发中,Null Pointer Dereference 是一种常见的错误,它发生在程序试图访问或操作一个空指针指向的内存位置时,这种情况通常会导致程序崩溃,给 debug 工作带来很大困扰,今天,我们将探讨如何解决 Null Pointer Dereference 报错,需要的朋友可以参考下
    2024-07-07
  • C语言实现循环单链表的示例代码

    C语言实现循环单链表的示例代码

    这篇文章主要给大家详细介绍了C语言如何实现循环单链表,文章通过代码示例讲解的非常详细,对我们的学习或工作有一定的参考价值,感兴趣的小伙伴跟着小编一起来看看吧
    2023-08-08

最新评论