题目描述
给你一个长度为
n
下标从 0 开始的整数数组maxHeights
。
你的任务是在坐标轴上建n
座塔。第i
座塔的下标为i
,高度为heights[i]
。
如果以下条件满足,我们称这些塔是 美丽 的:
1 <= heights[i] <= maxHeights[i]
heights
是一个 山脉 数组。
如果存在下标i
满足以下条件,那么我们称数组heights
是一个 山脉 数组:
- 对于所有
0 < j <= i
,都有heights[j - 1] <= heights[j]
- 对于所有
i <= k < n - 1
,都有heights[k + 1] <= heights[k]
请你返回满足 美丽塔 要求的方案中,高度和的最大值 。
示例 1:
输入: maxHeights = [5,3,4,1,1]
输出: 13
解释: 和最大的美丽塔方案为 heights = [5,3,3,1,1] ,这是一个美丽塔方案,因为:
- 1 <= heights[i] <= maxHeights[i]
- heights 是个山脉数组,峰值在 i = 0 处。
13 是所有美丽塔方案中的最大高度和。
题目解读
- 什么是美丽塔: 只有一个峰值。
- 举例:设给定
maxHeights = [5,3,4,1,1]
,则可以获取如下美丽塔。- 峰值在下标为
0
处的美丽塔为[5,3,4,1,1]
, 峰值为 5 - 峰值在下标为
1
处的美丽塔为[3,3,3,1,1]
, 峰值为 3 - 峰值在下标为
2
处的美丽塔为[3,3,4,1,1]
, 峰值为 4 - 峰值在下标为
3
处的美丽塔为[1,1,1,1,1]
, 峰值为 1 - 峰值在下标为
4
处的美丽塔为[1,1,1,1,1]
, 峰值为 1 - 即峰值在下标为
i
处的美丽塔满足两个条件,其左边非递减,右边非递增关系。- 左边非递减:即
j∈[1,i]
时,均满足heights[j−1]<=heights[j]
。 - 右边非递增:即
j∈[i,n−2]
,均满足heights[j]>=heights[j+1]
。
- 左边非递减:即
- 峰值在下标为
- 然后获取包含最大高度和的美丽塔。
- 问题首先就变成了怎么求美丽塔的高度和。
- 这种限制条件为递增或递减的问题可以考虑单调栈。
求非递减
非递减原理图
- x轴表示下标,黑色折现图表示允许建造的最大高度。红色折线图表示峰值在下标为
7
处的美丽塔高度情况。 - 可以看到,如果本来就是非递减的,那么保持原样,如果出现递减的情况了会将非递减的部分变成红色的相等部分。非递减原理如下图
单调栈的应用
- 单调栈中存储的是单调高度对应的数据下标。比如我们要求非递减部分,就可以使用一个非递减单调栈存储值。
- 当要处理的元素
k
小于单调栈的元素了,那么就将栈中大于k
的元素依次出栈,始终保持单调状态。
while (!stack1.empty() && maxHeights[i] < maxHeights[stack1.top()]) {
stack1.pop();
}
-
设以下标
i
处的值为峰值的左边非递减部分和为prefix[i]
,右边非递增部分和为suffix[i]
-
求
prefix[3]
,我们通过非递减单调栈找到最近的比较小的元素下标即1
(这时候大于maxHeights[3]
的值就不存在了)则prefix[3] = prefix[1] + (3-1) * maxHeights[3]
。prefix[3]
计算原理图如下:
-
这样遍历从0开始正序遍历所有元素就可以求出
prefix[i]
。 -
同理逆序遍历所有元素就可以求出所有的
suffix[i]
。
代码
long long maximumSumOfHeights(vector<int>& maxHeights) {
int n = maxHeights.size();
long long res = 0;
vector<long long> prefix(n), suffix(n);
//stack1 表示非递减栈,stack2表示非递增栈。
stack<int> stack1, stack2;
//求prefix
for (int i = 0; i < n; i++) {
while (!stack1.empty() && maxHeights[i]< maxHeights[stack1.top()]) {
stack1.pop();
}
if (stack1.empty()) {
cout<<i<<endl;
prefix[i] = (long long)(i + 1) * maxHeights[i];
} else {
cout<<i<<" "<<stack1.top()<<endl;
prefix[i] = prefix[stack1.top()] + (long long)(i - stack1.top()) * maxHeights[i];
}
stack1.emplace(i);
}
// 求suffix同时获取结果。
for (int i = n - 1; i >= 0; i--) {
while (!stack2.empty() && maxHeights[i] < maxHeights[stack2.top()]) {
stack2.pop();
}
if (stack2.empty()) {
suffix[i] = (long long)(n - i) * maxHeights[i];
} else {
suffix[i] = suffix[stack2.top()] + (long long)(stack2.top() - i) * maxHeights[i];
}
stack2.emplace(i);
res = max(res, prefix[i] + suffix[i] - maxHeights[i]);
}
return res;
}