- 作者:老汪软件技巧
- 发表时间:2023-12-30 01:00
- 浏览量:
题目链接
.2866 美丽塔 II : 2072
题目描述
给你一个长度为nnn 下标从000 开始的整数数组 。
你的任务是在坐标轴上建nnn 座塔。第iii 座塔的下标为iii ,高度为[i][i][i] 。
如果以下条件满足,我们称这些塔是 美丽 的:
如果存在下标iii 满足以下条件,那么我们称数组s 是一个 山状 数组:
请你返回满足 美丽塔 要求的方案中,高度和的最大值 。
示例 1:
输入: = [5,3,4,1,1]
输出:13
解释:和最大的美丽塔方案为 = [5,3,3,1,1] ,这是一个美丽塔方案,因为:
示例 2:
输入: = [6,5,3,9,2,7]
输出:22
解释: 和最大的美丽塔方案为 = [3,3,3,9,2,2] ,这是一个美丽塔方案,因为:
示例 3:
输入: = [3,2,5,5,2,3]
输出:18
解释:和最大的美丽塔方案为 = [2,2,5,5,2,2] ,这是一个美丽塔方案,因为:
提示: 解法:单调栈 + 前后缀分解
我们定义 和:
为了便于我们操作,我们将 和 都偏移一个长度,即 和 的长度都为n+1n + 1n+1。
举例 :
对于=[5,3,4,1,1] = [5,3,4,1,1]=[5,3,4,1,1],则它的 和 分别为:
那么最大的美丽塔高度和为max{pre[i]+suf[i]}(0≤i≤n)max\{ pre[i] + suf[i]\} \quad (0 \leq i \leq n)max{pre[i]+suf[i]}(0≤i≤n)
现在问题的关键在于如何求出 和。
我们可以使用单调栈。
对于 ,我们使用一个栈,从小到大的记录元素下标 (从栈底到栈顶)。假设当前遍历到的元素为[i][i][i],并且栈顶元素 大于等于 当前元素,即[()]≥[i][()] \geq [i][()]≥[i],那么我们就要不断地弹出栈顶元素。
上述操作完成之后,要么栈顶元素小于当前元素,即[()]要么此时栈为空。
我们就设jjj 为当前的栈顶元素,即j=()j = ()j=();如果栈为空,就设置j=−1j = -1j=−1。
那么此时(j,i](j,i](j,i] 这一区间的值都应该是[i][i][i],总和就是sum=(i−j)×[i]sum = (i - j) \times [i]sum=(i−j)×[i]。
所以此时pre[i]=sum+pre[j]pre[i] = sum + pre[j]pre[i]=sum+pre[j]。
对于求 也是同理。
时间复杂度:O(n)O(n)O(n)
C++代码:
using LL = long long;
class Solution {
public:
long long maximumSumOfHeights(vector& nums) {
int n = nums.size();
vector pre(n + 1) , suf(n + 1);
stack stk{{-1}};
for(int i = 0;i < n;i++){
while(stk.size() > 1 && nums[stk.top()] >= nums[i]){
stk.pop();
}
int j = stk.top();
pre[i + 1] += (i - j) * 1LL * nums[i];
pre[i + 1] += pre[j + 1];
stk.push(i);
}
//清空栈
while(!stk.empty()) stk.pop();
stk.push(n);
for(int i = n - 1;i >= 0;i--){
while(stk.size() > 1 && nums[stk.top()] >= nums[i]){
stk.pop();
}
int j = stk.top();
suf[i] += (j - i) * 1LL * nums[i];
suf[i] += suf[j];
stk.push(i);
}
LL ans = 0;
for(int i = 0;i <= n;i++){
ans = max(pre[i] + suf[i] , ans);
}
return ans;
}
};