好子数组的最大分数
难度:
标签:
题目描述
代码结果
运行时间: 71 ms, 内存: 25.6 MB
/*
* 给你一个整数数组 nums(下标从 0 开始)和一个整数 k。
* 一个子数组 (i, j) 的分数定义为 min(nums[i], nums[i+1], ..., nums[j]) * (j - i + 1)。
* 一个好子数组的两个端点下标需要满足 i <= k <= j。
* 请你返回好子数组的最大可能分数。
*/
import java.util.stream.IntStream;
public class Solution {
public int maximumScore(int[] nums, int k) {
int n = nums.length;
int[] leftMin = new int[n];
int[] rightMin = new int[n];
IntStream.range(0, n).forEach(i -> leftMin[i] = rightMin[i] = nums[i]);
for (int i = k - 1; i >= 0; i--) {
leftMin[i] = Math.min(leftMin[i], leftMin[i + 1]);
}
for (int i = k + 1; i < n; i++) {
rightMin[i] = Math.min(rightMin[i], rightMin[i - 1]);
}
int maxScore = nums[k];
int minVal = nums[k];
int left = k, right = k;
while (left > 0 || right < n - 1) {
if (left == 0) {
right++;
} else if (right == n - 1) {
left--;
} else if (nums[left - 1] < nums[right + 1]) {
right++;
} else {
left--;
}
minVal = Math.min(leftMin[left], rightMin[right]);
maxScore = Math.max(maxScore, minVal * (right - left + 1));
}
return maxScore;
}
}
解释
方法:
此题解采用双指针法,以 k 为中心向两边扩展。维护一个变量 m 来记录当前考虑的最小值,初始为 nums[k]。向左右两边扩展时,若当前指针指向的元素大于等于 m,则继续移动指针,直到遇到更小的元素或边界。每次移动指针后,更新最大分数 ans 和 m 的值。当 ans 大于等于 m 乘以数组长度 n 时,结束循环。
时间复杂度:
O(n)
空间复杂度:
O(1)
代码细节讲解
🦆
解题思路中提到的双指针法在更新最小值`m`的逻辑为何选择使用`max(nums[i], nums[k])`,而不是继续使用`nums[k]`作为最小值的参考?
▷🦆
在题解中,为什么要在数组`nums`末尾添加一个0,这样的处理会对算法的结果产生什么样的影响?
▷🦆
题解中提到当`ans < m * n`时继续循环,为什么选择这样的循环结束条件,它是基于什么样的考虑?
▷