1793. 好子数组的最大分数
给你一个整数数组nums
(下标从0
开始)和一个整数k
。
一个子数组(i, j)
的 分数 定义为min(nums[i], nums[i+1], ..., nums[j]) * (j - i + 1)
。一个 好 子数组的两个端点下标需要满足i <= k <= j
。
请你返回 好 子数组的最大可能 分数 。
示例 1:
输入:nums = [1,4,3,7,4,5], k = 3
输出:15
解释:最优子数组的左右端点下标是 (1, 5) ,分数为 min(4,3,7,4,5) * (5-1+1) = 3 * 5 = 15 。
示例 2:
输入:nums = [5,5,4,5,4,1,1,1], k = 0
输出:20
解释:最优子数组的左右端点下标是 (0, 4) ,分数为 min(5,5,4,5,4) * (4-0+1) = 4 * 5 = 20 。
题目分析
单调栈
解题思路:
- 维持一个单调递减栈,用于存储数组元素的下标
- 遍历数组 nums,对于每个元素 nums[i],执行以下步骤:
- 如果栈不为空且当前元素 nums[i] 小于栈顶元素对应的值 nums[stack.peek()],说明栈顶元素无法成为好子数组的右端点了。此时需要将栈顶元素出栈,并计算以栈顶元素为右端点的最大可能分数。分数计算公式为
nums[stack.pop()] * (i - stack.peek() - 1)
- 将当前元素下标 i 入栈
- 如果栈不为空且当前元素 nums[i] 小于栈顶元素对应的值 nums[stack.peek()],说明栈顶元素无法成为好子数组的右端点了。此时需要将栈顶元素出栈,并计算以栈顶元素为右端点的最大可能分数。分数计算公式为
- 遍历完成后清空栈,此时右端点为
nums.length - 1
单调栈详解及相关 Leetcode 题解见 Leetcode 单调栈详解
class Solution {public int maximumScore(int[] nums, int k) {int ans = 0;// 单调递减栈Stack<Integer> stack = new Stack<>();for (int i = 0; i < nums.length; i++) {while (!stack.isEmpty() && nums[stack.peek()] >= nums[i]) {int h = nums[stack.pop()];int left = stack.isEmpty() ? 0 : stack.peek() + 1;int right = i - 1;int w = right - left + 1;if (left <= k && k <= right) {ans = Math.max(ans, w * h);}}stack.push(i);}while (!stack.isEmpty()) {int h = nums[stack.pop()];int right = nums.length - 1;int left = stack.isEmpty() ? 0 : stack.peek() + 1;int w = right - left + 1;if (left <= k && k <= right) {ans = Math.max(ans, w * h);}}return ans;}
}
双指针
解题思路:以下标为k的元素作为中心向两边扩展,每次扩展一个单位。取左右边界的较大者作为下一个要扩展的区域。
[left, right]
表示下标 left 到 right 的区域为已经扩展过的区间curValue = (right - left + 1) * min
表示包含 k 在内且区间长度为(right - left + 1)
的最大值;
双指针,顾名思义就是同时使用两个指针,在序列、链表结构上指向的是位置,在树、图结构中指向的是节点,通过或同向移动,或相向移动来维护、统计信息
class Solution {public int maximumScore(int[] nums, int k) {int n = nums.length;int ans = nums[k];int min = nums[k];int left = k;int right = k;while (left > 0 || right + 1 < n) {if (right + 1 >= n || (left > 0 && nums[left - 1] > nums[right + 1])) {left--;min = Math.min(min, nums[left]);} else {right++;min = Math.min(min, nums[right]);}ans = Math.max(ans, (right - left + 1) * min);}return ans;}
}