题目
给你一个整数数组 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 。
提示:
1 <= nums.length <= 1051 <= nums[i] <= 2 * 1040 <= k < nums.length
题解
这道题和 11. 盛最多水的容器 非常类似,所以我第一时间就想到的是贪心法。
首先是设好双指针 i, j,显然双指针只能从中间往外移动,然后思考根据什么规则来移动指针。
比较 nums[i] 和 nums[j] 的大小是没有意义的,因为我们完全可以把 i 到 j 之间的值全部看做最小值 min_num,超出最小值的部分是没有意义的。
真正影响的,是指针两端的值,也就是 nums[i-1] 和 nums[j+1] 的大小。
所以我们很直观的思路就是将指针往大的那一方向扩张。
那么这种策略有没有可能漏掉最优解的情况呢?

现在我们假设最优情况为 (i*,j*),那么由于指针从中间往外扩张,必然有一个指针先到达最优位置,我们假设右指针 j 已经到达了 j*,现在左指针 i 还在 k 处。
那么我们首先可以肯定:j*+1 处的值,比 i* 到 j* 之间所有的值都要小。否则 (i*,j*+1) 就是比 (i*,j*) 更优的解,这与假设矛盾。
所以此时我们比较 nums[i-1] 和 nums[j+1] 的大小时,肯定是左边的更大,因此左指针 i 往左移。
左移之后,还是面临同样的情况,因此在左指针 i 到达 i* 之前,移动的一定是左指针,也就是说该策略一定能匹配到最优解。
最终代码如下:
class Solution:
def maximumScore(self, nums, k):
n = len(nums)
min_num = nums[k]
max_value = min_num
i = k
j = k
while i > 0 or j < n-1:
if i == 0:
j += 1
elif j == n-1:
i -= 1
elif nums[i-1] > nums[j+1]:
i -= 1
else:
j += 1
min_num = min(min_num, min(nums[i], nums[j]))
max_value = max(max_value, min_num*(j - i + 1))
return max_value

