单调栈or动态规划——接雨水

原题在这里:

概述题意,给一个数组,求填平数组(凹处的高低差)所需面积。

想过双指针两端考虑高点收缩;

想过从每一个高度入手;

也想过单调栈(但没想明白怎么用)。

然后debug一个小时用了一个自己的解法:

  去重找峰值,删除峰的凹峰【此后数组类型就是(递增+)递减了】,然后遍历。

 

复制代码
class Solution
{
    vector<int> num, m;
    vector<int> pick()
    {
        vector<int> n(0);
        int l = m.size();
        if (l > 2)
        {
            if (num[m[0]] > num[m[1]])
                n.emplace_back(m[0]);
            for (int i = 1; i < l - 1; ++i)
                if (num[m[i]] > num[m[i - 1]] && num[m[i]] > num[m[i + 1]])
                    n.emplace_back(m[i]);
            if (num[m[l - 1]] > num[m[l - 2]])
                n.emplace_back(m[l - 1]);
            return n;
        }
        return m;
    }

public:
    int trap(vector<int> &height)
    {
        int ans = 0, l = height.size();
        for (int i = 0; i < l; ++i)
        {
            num.emplace_back(height[i]);
            if (i == 0 || height[i] != height[i - 1])
                m.emplace_back(i);
        }
        m = pick();
        for (int i = 1, mx = height[m[0]]; i < m.size() - 1; ++i)
        {
            mx = max(mx, height[m[i]]);
            if (mx > height[m[i]] && height[m[i]] < height[m[i + 1]])
                m.erase(m.begin() + i), i = max(i - 2, 0);
        }
        l = m.size();
        //处理完后只有(递增+)递减
        for (int i = 1; i < l; ++i)
        {
            int x = m[i - 1], y = m[i];
            for (int j = x + 1; j < y; ++j)
                ans += max(min(num[x], num[y]) - num[j], 0);
        }
        return ans;
    }
};
线性复杂度
复制代码

 

比较满意的一点是,解法是线性复杂度的。

然后看官解一如既往的优秀:

  1.动态规划

    一图看懂:

 

 

简直太棒了,两端遍历维护最大值,然后遍历min[i]-num[i]即可,很直观的O(n)解法。

完全是数学类型解法,优秀。

code:

 

复制代码
class Solution
{
public:
    int trap(vector<int> &height)
    {
        int ans = 0, l = height.size();
        if (l > 2)
        {
            vector<int> left(height), right(height);
            for (int i = 1; i < l; ++i)
                left[i] = max(left[i], left[i - 1]);
            for (int i = l - 2; i >= 0; --i)
                right[i] = max(right[i], right[i + 1]);
            for (int i = 0; i < l; ++i)
                ans += min(left[i], right[i]) - height[i];
        }
        return ans;
    }
};
View Code
复制代码

 

 

  2.单调栈

  当前高度小于等于栈顶高度,入栈,指针后移。

  当前高度大于栈顶高度,出栈,计算出当前墙和栈顶的墙之间水的多少,然后计算当前的高度和新栈的高度的关系,重复第 2 步。

  直到当前墙的高度不大于栈顶高度或者栈空,然后把当前墙入栈,指针后移。

code:

复制代码
class Solution
{
public:
    int trap(vector<int> &height)
    {
        int ans = 0, l = height.size();
        stack<int> st;
        for (int i = 0; i < l; ++i)
        {
            while (!st.empty() && height[st.top()] < height[i])
            {
                int left = st.top();
                st.pop();
                if (st.empty())
                    break;
                int l = st.top();
                ans += (i - l - 1) * (min(height[i], height[l]) - height[left]);
            }
            st.push(i);
        }
        return ans;
    }
};
stack
复制代码

 

  3.双指针

  如上。

【Over】

posted @   Renhr  阅读(84)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!
点击右上角即可分享
微信分享提示