Medium
题目描述
给你一个长度为 n 的整数数组 heights,表示 n 座连续塔的砖块数量。你的任务是移除一些砖块来形成山形塔排列。在这种排列中,塔的高度先非递减,达到一个或多个连续塔的最大峰值,然后非递增。
返回山形塔排列的最大可能高度总和。
示例 1:
输入:heights = [5,3,4,1,1]
输出:13
解释:我们移除一些砖块使得 heights = [5,3,3,1,1],峰值在索引 0 处。
示例 2:
输入:heights = [6,5,3,9,2,7]
输出:22
解释:我们移除一些砖块使得 heights = [3,3,3,9,2,2],峰值在索引 3 处。
示例 3:
输入:heights = [3,2,5,5,2,3]
输出:18
解释:我们移除一些砖块使得 heights = [2,2,5,5,2,2],峰值在索引 2 或 3 处。
约束条件:
1 <= n == heights.length <= 10³1 <= heights[i] <= 10⁹
解题思路
这是一道关于山形数组的问题,需要找到最大可能的山形塔高度总和。
核心思路:
- 枚举每个位置作为峰值点
- 对于每个峰值点,分别向左和向右构建山形结构
- 向左时,每个位置的高度不能超过右边位置的高度(非递增)
- 向右时,每个位置的高度不能超过左边位置的高度(非递减)
算法步骤:
- 遍历数组的每个位置
i作为峰值 - 从峰值向左扫描:每个位置的高度 = min(原高度, 右边位置的最终高度)
- 从峰值向右扫描:每个位置的高度 = min(原高度, 左边位置的最终高度)
- 计算当前峰值下的总高度,更新最大值
这种方法确保了山形结构的正确性:峰值左侧非递增,右侧非递减。
时间复杂度: O(n²) - 对每个峰值位置都需要扫描整个数组 空间复杂度: O(n) - 需要额外数组存储调整后的高度
虽然存在 O(n) 的单调栈优化解法,但对于此题的数据规模(n ≤ 1000),暴力解法已经足够高效。
代码实现
class Solution {
public:
long long maximumSumOfHeights(vector<int>& heights) {
int n = heights.size();
long long maxSum = 0;
for (int peak = 0; peak < n; peak++) {
vector<long long> adjusted(n);
adjusted[peak] = heights[peak];
// 向左填充(非递增)
for (int i = peak - 1; i >= 0; i--) {
adjusted[i] = min((long long)heights[i], adjusted[i + 1]);
}
// 向右填充(非递减)
for (int i = peak + 1; i < n; i++) {
adjusted[i] = min((long long)heights[i], adjusted[i - 1]);
}
// 计算总和
long long currentSum = 0;
for (int i = 0; i < n; i++) {
currentSum += adjusted[i];
}
maxSum = max(maxSum, currentSum);
}
return maxSum;
}
};
class Solution:
def maximumSumOfHeights(self, heights: List[int]) -> int:
n = len(heights)
max_sum = 0
for peak in range(n):
adjusted = [0] * n
adjusted[peak] = heights[peak]
# 向左填充(非递增)
for i in range(peak - 1, -1, -1):
adjusted[i] = min(heights[i], adjusted[i + 1])
# 向右填充(非递减)
for i in range(peak + 1, n):
adjusted[i] = min(heights[i], adjusted[i - 1])
# 计算总和
current_sum = sum(adjusted)
max_sum = max(max_sum, current_sum)
return max_sum
public class Solution {
public long MaximumSumOfHeights(int[] heights) {
int n = heights.Length;
long maxSum = 0;
for (int peak = 0; peak < n; peak++) {
long[] adjusted = new long[n];
adjusted[peak] = heights[peak];
// 向左填充(非递增)
for (int i = peak - 1; i >= 0; i--) {
adjusted[i] = Math.Min(heights[i], adjusted[i + 1]);
}
// 向右填充(非递减)
for (int i = peak + 1; i < n; i++) {
adjusted[i] = Math.Min(heights[i], adjusted[i - 1]);
}
// 计算总和
long currentSum = 0;
for (int i = 0; i < n; i++) {
currentSum += adjusted[i];
}
maxSum = Math.Max(maxSum, currentSum);
}
return maxSum;
}
}
/**
* @param {number[]} heights
* @return {number}
*/
var maximumSumOfHeights = function(heights) {
const n = heights.length;
let maxSum = 0;
for (let peak = 0; peak < n; peak++) {
const adjusted = new Array(n);
adjusted[peak] = heights[peak];
// 向左填充(非递增)
for (let i = peak - 1; i >= 0; i--) {
adjusted[i] = Math.min(heights[i], adjusted[i + 1]);
}
// 向右填充(非递减)
for (let i = peak + 1; i < n; i++) {
adjusted[i] = Math.min(heights[i], adjusted[i - 1]);
}
// 计算总和
let currentSum = 0;
for (let i = 0; i < n; i++) {
currentSum += adjusted[i];
}
maxSum = Math.max(maxSum, currentSum);
}
return maxSum;
};
复杂度分析
| 复杂度类型 | 大小 | 说明 |
|---|---|---|
| 时间复杂度 | O(n²) | 枚举 n 个峰值位置,每次需要 O(n) 时间构建山形数组 |
| 空间复杂度 | O(n) | 需要额外数组存储调整后的高度值 |