• 美丽塔O(n)解法单调栈


    题目

    见上一篇: 较难算法美丽塔时间复杂度O(n)-CSDN博客

    本文涉及的基础知识点

    单调栈分类、封装和总结icon-default.png?t=N7T8https://blog.csdn.net/he_zhidan/article/details/135150163

    时间复杂度

    O(n)

    分析

    接着上篇。从左向右依次处理Left,处理Left[i]时,从右向左寻找第一个符合maxHeights[j]=maxHeights[j2],那j1永远不会被选到。比如:{1,3,2,4,5},由于2在3右边,且小于3,则无论如何不会选中3。{1,2,2.....},后面无论有什么数,都不会选中第一个2,要么是其他数,要么是第二个2。
    可以用栈实现,入栈maxHeights[i]之前,先出栈大于等于maxHeights[i]的数,剩余的都小于maxHeights[i]的数。也就是栈按升序排序的。由于maxHeights[i]和heights[i]都可以通过索引查询,栈中只需要记录索引。
    Right类似,不再累赘。

    样例分析

    maxHeights

    Left的栈情况

    {1,2,3,4,5}

    1

    12

    123

    1234

    12345

    {5,4,3,2,1}

    5

    4

    3

    2

    1

    {1,2,4,3,5}

    1

    12

    124

    123

    1235

    {3,1,2}

    3

    1

    12

    {2,1,3}

    2

    1

    13

    代码

    核心代码

    1. class Solution {
    2. public:
    3.     long long maximumSumOfHeights(vector<int>& maxHeights) {
    4.         m_c = maxHeights.size();
    5.         m_vLeft.resize(m_c);
    6.         m_vRight.resize(m_c);
    7.         {//处理左边
    8.             stack<int> sta;//记录做边的索引
    9.             for (int i = 0; i < m_c; i++)
    10.             {
    11.                 const auto& h = maxHeights[i];
    12.                 while (sta.size() && (maxHeights[sta.top()] >= h))
    13.                 {
    14.                     sta.pop();//左边比右边大,不会被选中
    15.                 }
    16.                 if (sta.size())
    17.                 {
    18.                     m_vLeft[i] = m_vLeft[sta.top()] + (long long)h * (i - sta.top());
    19.                 }
    20.                 else
    21.                 {
    22.                     m_vLeft[i] =  (long long)h * (i -(-1) );
    23.                 }
    24.                 sta.emplace(i);
    25.             }
    26.         }
    27.         {//处理右边
    28.             stack<int> sta;//记录做边的索引
    29.             for (int i = m_c - 1; i >= 0; i--)
    30.             {
    31.                 const auto& h = maxHeights[i];
    32.                 while (sta.size() && (maxHeights[sta.top()] >= h))
    33.                 {
    34.                     sta.pop();//左边比右边大,不会被选中
    35.                 }
    36.                 if (sta.size())
    37.                 {
    38.                     m_vRight[i] = m_vRight[sta.top()] + (long long)h * (sta.top()-i);
    39.                 }
    40.                 else
    41.                 {
    42.                     m_vRight[i] = (long long)h * (m_c-i);
    43.                 }
    44.                 sta.emplace(i);
    45.             }
    46.         }
    47.         
    48.         long long llRet = 0;
    49.         for (int i = 0; i < m_c; i++)
    50.         {//假定i是山顶            
    51.             long long llCur = m_vLeft[i] + m_vRight[i] - maxHeights[i];
    52.             llRet = max(llRet, llCur);
    53.         }
    54.         return llRet;
    55.     }
    56.     int m_c;
    57.     vector<long long> m_vLeft, m_vRight;
    58. };

    测试用代码

    class CDebug : public Solution
    {
    public:
        long long maximumSumOfHeights(vector& maxHeights, vector& vLeft, vector& vRight)
        {
            vector maxs(maxHeights.begin(), maxHeights.end());
            long long llRet = Solution::maximumSumOfHeights(maxs);
            for (int i = 0 ; i < vLeft.size();i++ )
            {
                assert(m_vLeft[i] == vLeft[i]);
                assert(m_vRight[i] == vRight[i]);
            }

            //调试用代码
            std::cout << "Left: ";
            for (int i = 0; i < m_c; i++)
            {
                std::cout << m_vLeft[i] << " ";
            }
            std::cout << std::endl;
            std::cout << "Right: ";
            for (int i = 0; i < m_c; i++)
            {
                std::cout << m_vRight[i] << " ";
            }
            std::cout << std::endl;
            return llRet;
        }
    };
    int main()
    {
        vector < vector>> param = { {{1,2,3,4,5} ,{1,3,6,10,15},{5,8,9,8,5}} ,
            {{5,4,3,2,1},{5,8,9,8,5},{15,10,6,3,1}} ,
            {{1,2,4,3,5},{1,3,7,9,14},{5,8,10,6,5}},
        {{3,1,2}, {3,2,4},{5,2,2}},
        {{2,1,3},{2,2,5},{4,2,3}},
            {{1000000000,1000000000,1000000000},{1000000000,2000000000,3000000000LL},{3000000000LL,2000000000,1000000000}} };
        for (auto& vv : param)
        {
            auto res = CDebug().maximumSumOfHeights(vv[0], vv[1], vv[2]);
        }
        //auto res = Solution().maxPalindromes("rire", 3);

    //CConsole::Out(res);
    }

    使用封装类的代码

    1. class CRangIndex
    2. {
    3. public:
    4. template<class _Pr>
    5. CRangIndex(int iVectorSize, _Pr CurIndexCmpStackTopIndex)
    6. {
    7. m_c = iVectorSize;
    8. m_vLeft.assign(m_c, -1);
    9. m_vRight.assign(m_c, m_c);
    10. stack<int> sta;
    11. for (int i = 0; i < m_c; i++)
    12. {
    13. while (sta.size() && (CurIndexCmpStackTopIndex(i, sta.top())))
    14. {
    15. m_vRight[sta.top()] = i;
    16. sta.pop();
    17. }
    18. if (sta.size())
    19. {
    20. m_vLeft[i] = sta.top();
    21. }
    22. sta.emplace(i);
    23. }
    24. }
    25. template<class _Pr>
    26. CRangIndex(const vector<int>& nums, _Pr CurValueCmpStackTopValue)
    27. {
    28. m_c = nums.size();
    29. m_vLeft.assign(m_c, -1);
    30. m_vRight.assign(m_c, m_c);
    31. stack<int> sta;
    32. for (int i = 0; i < m_c; i++)
    33. {
    34. while (sta.size() && (CurValueCmpStackTopValue(nums[i], nums[sta.top()])))
    35. {
    36. m_vRight[sta.top()] = i;
    37. sta.pop();
    38. }
    39. if (sta.size())
    40. {
    41. m_vLeft[i] = sta.top();
    42. }
    43. sta.emplace(i);
    44. }
    45. }
    46. int m_c;
    47. vector<int> m_vLeft, m_vRight;//vLeft[i] 从右向左第一个小于nums[i] ;vRight[i] 是第一个小于等于nums[i]。
    48. };
    49. class Solution {
    50. public:
    51. long long maximumSumOfHeights(vector<int>& maxHeights) {
    52. CRangIndex ri(maxHeights, std::less<>());
    53. m_vLeft.resize(ri.m_c);
    54. for (int i = 0; i < ri.m_c; i++)
    55. {
    56. m_vLeft[i] = (-1 == ri.m_vLeft[i]) ? 0 : m_vLeft[ri.m_vLeft[i]];
    57. m_vLeft[i] += ((long long)i - ri.m_vLeft[i]) * maxHeights[i];
    58. }
    59. m_vRight.resize(ri.m_c);
    60. long long llRet = 0;
    61. for (int i = ri.m_c - 1; i >= 0; i--)
    62. {
    63. m_vRight[i] = (ri.m_c == ri.m_vRight[i]) ? 0 : m_vRight[ri.m_vRight[i]];
    64. m_vRight[i] += ((long long)ri.m_vRight[i] - i ) * maxHeights[i];
    65. long long llCur = m_vLeft[i] + m_vRight[i] - maxHeights[i];
    66. llRet = max(llRet, llCur);
    67. }
    68. return llRet;
    69. }
    70. int m_c;
    71. vector<long long> m_vLeft, m_vRight;
    72. };

    下载

    源码: 【免费】美丽塔单调栈O(n)解法资源-CSDN文库

    https://img-blog.csdnimg.cn/ea2601b3918f4aef836b5fe30da2ebf7.gif#pic_center#pic_center

    其它

    视频课程

    如果你觉得复杂,想从简单的算法开始,可以学习我的视频课程。

    https://edu.csdn.net/course/detail/38771

    我的其它课程

    https://edu.csdn.net/lecturer/6176

    测试环境

    win7 VS2019 C++17 或Win10 VS2022 Ck++17

    相关下载

    算法精讲《闻缺陷则喜算法册》doc版

    https://download.csdn.net/download/he_zhidan/88348653

    作者人生格言

    有所得,以墨记之,故曰墨家

    闻缺陷则喜。问题发现得越早,越给老板省钱。

    算法是程序的灵魂

    https://img-blog.csdnimg.cn/f95ddae62a4e43a68295601c723f92fb.gif#pic_center

  • 相关阅读:
    13个学习技巧,让你每天进步一点点
    扩散模型(Diffusion Model,DDPM,GLIDE,DALLE2,Stable Diffusion)
    leetcode16最接近的三数之和 (排序+ 双指针)
    量表如何分析?
    创建百科词条 烘托人物形象 提升形象力
    Struts.xml 配置文件说明
    vue安装使用swiper
    基于java的驾校驾照在线考试系统
    【笔记】《C++性能优化指南》Ch3 测量性能
    万字详解数据仓库、数据湖、数据中台和湖仓一体
  • 原文地址:https://blog.csdn.net/he_zhidan/article/details/133346130