单调栈,LeetCode 1793. 好子数组的最大分数
一、题目
1、题目描述
给你一个整数数组
nums
(下标从 0 开始)和一个整数k
。一个子数组
(i, j)
的 分数 定义为min(nums[i], nums[i+1], ..., nums[j]) * (j - i + 1)
。一个 好 子数组的两个端点下标需要满足i <= k <= j
。请你返回 好 子数组的最大可能 分数 。
2、接口描述
class Solution {
public:
int maximumScore(vector<int>& nums, int k) {
}
};
3、原题链接
1793. 好子数组的最大分数
二、解题报告
1、思路分析
贪心+双指针
和84. 柱状图中最大的矩形类似, 本质都是求最大矩形面积,只不过本题要求矩形包含k
那么我们考虑从k开始,双指针向两边遍历
双指针l,r初始指向k,如果nums[l - 1]大于nums[r + 1],就l--,否则r++
然后维护区间[l, r]内的最小值mi,矩形面积就是mi * (r - l + 1)
下面证明贪心策略的正确性:
假设最终答案矩形边界为L,R
那么一定有nums[L - 1] < nums[L],nums[R + 1] < nums[R],否则矩形可以进一步扩大
我们只需证明l ,r最终一定停留在L,R的位置
不失一般性的假设l先抵达L,此时由于nums[L - 1] < mi <= nums[r],故r会一直右移直到R
反之如果r先抵达R,亦然
2、复杂度
时间复杂度: O(n)空间复杂度:O(1)
3、代码详解
class Solution {
public:
int maximumScore(vector<int>& nums, int k) {
int n = nums.size(), l = k, r = k, ret = nums[k];
for(int i = 0, mi = nums[k]; i < n - 1; i++){
if(r == n - 1 || (l && nums[l - 1] > nums[r + 1]))
mi = min(mi, nums[--l]);
else
mi = min(mi, nums[++r]);
ret = max(ret, (r - l + 1) * mi);
}
return ret;
}
};