[M单调栈] lc2866. 美丽塔 II(单调栈+前后缀分解+经典好题+题单)

2024-01-25 04:36

本文主要是介绍[M单调栈] lc2866. 美丽塔 II(单调栈+前后缀分解+经典好题+题单),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 1. 题目来源
    • 2. 题目解析

1. 题目来源

链接:2866. 美丽塔 II

关联:

  • 关联博文:[M枚举] lc2865. 美丽塔 I(枚举+前后缀分解+题单)
  • 超高质量题解:[Java/Python3/C++]前后缀和+单调栈:以每个最大高度为峰值构造美丽塔【图解】

2. 题目解析

很有质量的一道题目了,难度应该评定低了…2000 分的题目。

承接上题,如果数据量放大后,断然不会用两层循环去解题。实际上选定 i 作为峰值时,后缀 和 前缀 的状态是固定的,我们只需要将 前缀、后缀 这两个数据处理好,是不是就可以直接获取到答案了。

思路:以后缀为例

  • 从后往前遍历数组,维护一个后缀和,该后缀和表示当前元素作为顶峰时,后缀的山脉高度总和。
    • 当目前的山脉比前面的高时,后缀和直接累加即可。
    • 当目前的山脉比前面的低时,就可以根据单调栈找到次高值将其山脉高度变为降序序列。这个时候,出栈的这部分山脉高度都会比当前山脉高,后缀和需要减去对应的差值。

单调栈的思路比较直接,但是编码过程中维护一些变量啥的、边界情况啥的 就比较难处理,属于十分易错的。


技巧:

  • 针对栈中第一次添加元素进来时,右区间还没有对应值,可以先给栈上加入哨兵节点,保证栈不为空,右区间哨兵节点:n,左区间哨兵节点 -1。

推荐阅读:超高质量题解:[Java/Python3/C++]前后缀和+单调栈:以每个最大高度为峰值构造美丽塔【图解】 这个图文结合,再自己手绘一下单调栈的情况就能很快速的理解了~


  • 时间复杂度 O ( n ) O(n) O(n)
  • 空间复杂度 O ( n ) O(n) O(n)

class Solution {
public:long long maximumSumOfHeights(vector<int>& maxHeights) {int n = maxHeights.size();vector<long long> sufSums(n);   // 后缀和数组stack<int> st;      // 单调栈st.push(n);         // 栈底为n表示后缀和边界long long sufS = 0; // 后缀和for(int i = n - 1; i >= 0; i--){while(st.size() > 1 && maxHeights[i] <= maxHeights[st.top()]){// 在到达栈底n之前,弹出位于当前位置右侧的小于等于当前位置最大高度的索引int t = st.top();   // 获取要弹出的元素st.pop();           // 弹出sufS -= (long long)maxHeights[t] * (st.top() - t);  // 后缀和减去弹出索引对应的区间包含的高度和}sufS += (long long)maxHeights[i] * (st.top() - i);      // 后缀和累加要加入的索引对应的区间包含的高度和sufSums[i] = sufS;      // 记录后缀和st.push(i);             // 元素入栈}while(!st.empty())st.pop(); // 清空栈st.push(-1);                // 栈底为-1表示前缀和边界long long res = 0;  // 结果值long long preS = 0; // 前缀和for(int i = 0; i < n; i++){while(st.size() > 1 && maxHeights[i] <= maxHeights[st.top()]){// 在到达栈底-1之前,弹出位于当前位置左侧的小于等于当前位置最大高度的索引int t = st.top();st.pop();preS -= (long long)maxHeights[t] * (t - st.top());  // 前缀和和减去弹出索引对应的区间包含的高度和}preS += (long long)maxHeights[i] * (i - st.top());      // 前缀和累加要加入的索引对应的区间包含的高度和res = max(res, preS + sufSums[i] - maxHeights[i]);      // 得到当前位置前后缀和,更新最大值st.push(i);     // 元素入栈}return res;        }
};

这篇关于[M单调栈] lc2866. 美丽塔 II(单调栈+前后缀分解+经典好题+题单)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/642101

相关文章

【Linux进阶】UNIX体系结构分解——操作系统,内核,shell

1.什么是操作系统? 从严格意义上说,可将操作系统定义为一种软件,它控制计算机硬件资源,提供程序运行环境。我们通常将这种软件称为内核(kerel),因为它相对较小,而且位于环境的核心。  从广义上说,操作系统包括了内核和一些其他软件,这些软件使得计算机能够发挥作用,并使计算机具有自己的特生。这里所说的其他软件包括系统实用程序(system utility)、应用程序、shell以及公用函数库等

一道经典Python程序样例带你飞速掌握Python的字典和列表

Python中的列表(list)和字典(dict)是两种常用的数据结构,它们在数据组织和存储方面有很大的不同。 列表(List) 列表是Python中的一种有序集合,可以随时添加和删除其中的元素。列表中的元素可以是任何数据类型,包括数字、字符串、其他列表等。列表使用方括号[]表示,元素之间用逗号,分隔。 定义和使用 # 定义一个列表 fruits = ['apple', 'banana

前端 CSS 经典:文字描边

前言:文字描边有两种实现方式 1. text-shadow 设置 8 个方向的文字阴影,缺点是只有八个方向,文字转角处可能有锯齿状。不支持文字透明,设置 color: transparent,文字会成描边颜色。 <!DOCTYPE html><html lang="en"><head><meta charset="utf-8" /><meta http-equiv="X-UA-Comp

Python分解多重列表对象,isinstance实现

“”“待打印的字符串列表:['ft','bt',['ad',['bm','dz','rc'],'mzd']]分析可知,该列表内既有字符对象,又有列表对象(Python允许列表对象不一致)现将所有字符依次打印并组成新的列表”“”a=['ft','bt',['ad',['bm','dz','rc'],'mzd']]x=[]def func(y):for i in y:if isinst

LeetCode:经典题之141、142 题解及延伸

系列目录 88.合并两个有序数组 52.螺旋数组 567.字符串的排列 643.子数组最大平均数 150.逆波兰表达式 61.旋转链表 160.相交链表 83.删除排序链表中的重复元素 389.找不同 1491.去掉最低工资和最高工资后的工资平均值 896.单调序列 206.反转链表 92.反转链表II 141.环形链表 142.环型链表 目录 系列目录141. 环形链表常量因子 1

【数据结构与算法 经典例题】使用队列实现栈(图文详解)

💓 博客主页:倔强的石头的CSDN主页               📝Gitee主页:倔强的石头的gitee主页    ⏩ 文章专栏:《数据结构与算法 经典例题》C语言                                   期待您的关注 ​​ 目录  一、问题描述 二、前置知识 三、解题思路 四、C语言实现代码 🍃队列实现代码:

海量数据处理经典思想

第一部分、十五道海量数据处理 1. 给定a、b两个文件,各存放50亿个url,每个url各占64字节,内存限制是4G,让你找出a、b文件共同的url?     方案1:可以估计每个文件安的大小为50G×64=320G,远远大于内存限制的4G。所以不可能将其完全加载到内存中处理。考虑采取分而治之的方法。 遍历文件a,对每个url求取,然后根据所取得的值将url分别存储到1000个小文件(

LeetCode:经典题之389 题解与延伸

系列目录 88.合并两个有序数组 52.螺旋数组 567.字符串的排列 643.子数组最大平均数 150.逆波兰表达式 61.旋转链表 160.相交链表 83.删除排序链表中的重复元素 389.找不同 1491.去掉最低工资和最高工资后的工资平均值 896.单调序列 206.反转链表 92.反转链表II 141.环形链表 142.环型链表 目录 系列目录389.找不同哈希表

代码随想录算法训练营第三十九天|62.不同路径 63. 不同路径 II 343.整数拆分 96.不同的二叉搜索树

LeetCode 62.不同路径 题目链接:62.不同路径 踩坑:二维的vector数组需要初始化,否则会报错访问空指针 思路: 确定动态数组的含义:dp[i][j]:到达(i,j)有多少条路经递推公式:dp[i][j] = dp[i-1][j] + dp[i][j-1]初始化动态数组:dp[0][0] = 1遍历顺序:从左到右,从上到下 代码: class Solution {pu

poj 3882(Stammering Aliens) 后缀数组 或者 hash

后缀数组:  构建后缀数组,注意要在字符串莫末尾加上一个没出现过的字符。然后可以2分或者直接扫描,直接扫描需要用单调队列来维护 VIEW CODE #include<cstdio>#include<algorithm>#include<iostream>#include<cmath>#include<queue>#include<stack>#include<string