A "good" subarray must contain index k. The score is the minimum element multiplied by the subarray length. The straightforward approach is to try all possible subarrays that include k, tracking the minimum as we extend each one. For each starting point at or before k, we extend rightward past k, updating the minimum and calculating the score at each step.
i from 0 to k:minEle with nums[i].i to n-1.minEle as we encounter each new element.j reaches k or beyond, calculate the score and update the result.For any subarray containing k, the minimum value decreases (or stays the same) as we expand outward from k. We can preprocess the array so that arr[i] represents the minimum value in the subarray from i to k (for left side) or from k to i (for right side). This creates sorted arrays on each side, allowing binary search to quickly find how far we can extend while maintaining at least a given minimum value.
k-1 down to 0, set arr[i] = min(arr[i], arr[i+1]).k+1 to n-1, set arr[i] = min(arr[i], arr[i-1]).minVal.minVal.class Solution:
def maximumScore(self, nums: List[int], k: int) -> int:
n, res = len(nums), 0
arr = nums[:]
for i in range(k - 1, -1, -1):
arr[i] = min(arr[i], arr[i + 1])
for i in range(k + 1, n):
arr[i] = min(arr[i], arr[i - 1])
left_arr = arr[:k+1]
right_arr = arr[k:]
def find_right(target):
lo, hi = 0, len(right_arr) - 1
pos = 0
while lo <= hi:
mid = (lo + hi) // 2
if right_arr[mid] >= target:
pos = mid
lo = mid + 1
else:
hi = mid - 1
return pos
for minVal in set(arr):
l = bisect_left(left_arr, minVal)
r = find_right(minVal)
res = max(res, minVal * (k - l + 1 + r))
return resThis is a space-optimized version of the previous approach. Instead of creating a separate array, we modify the input array directly. The left portion becomes non-decreasing toward k, and the right portion becomes non-increasing from k. We can then binary search directly on the modified input array.
k-1 down to 0, set nums[i] = min(nums[i], nums[i+1]).k+1 to n-1, set nums[i] = min(nums[i], nums[i-1]).[0, k]) with value >= target.[k, n-1]) with value >= target.class Solution:
def maximumScore(self, nums: List[int], k: int) -> int:
n, res = len(nums), 0
for i in range(k - 1, -1, -1):
nums[i] = min(nums[i], nums[i + 1])
for i in range(k + 1, n):
nums[i] = min(nums[i], nums[i - 1])
def find_left(target):
lo, hi = 0, k
while lo <= hi:
mid = (lo + hi) // 2
if nums[mid] < target:
lo = mid + 1
else:
hi = mid - 1
return lo
def find_right(target):
lo, hi = k, n - 1
while lo <= hi:
mid = (lo + hi) // 2
if nums[mid] >= target:
lo = mid + 1
else:
hi = mid - 1
return hi
for minVal in set(nums):
i = find_left(minVal)
j = find_right(minVal)
res = max(res, minVal * (j - i + 1))
return resThis problem is related to finding the largest rectangle in a histogram. For each element, we want to know how far left and right it can extend as the minimum. A monotonic stack helps us find the "next smaller element" boundaries efficiently. When we pop an element from the stack, we know its valid range, and we only count it if that range includes index k.
0 to n (using n as a sentinel to flush the stack).-1) to the current index.k, calculate the score.class Solution:
def maximumScore(self, nums: List[int], k: int) -> int:
n, res = len(nums), 0
stack = []
for i in range(n + 1):
while stack and (i == n or nums[stack[-1]] >= nums[i]):
mini = nums[stack.pop()]
j = stack[-1] if stack else -1
if j < k < i:
res = max(res, mini * (i - j - 1))
stack.append(i)
return resStart with just the element at index k as our subarray. To expand, we have two choices: go left or go right. The key insight is that we should always expand toward the larger neighbor. This greedy choice maximizes the minimum value we can maintain for as long as possible, leading to higher scores. We continue until we have expanded to cover the entire array.
l = r = k and track the current minimum starting with nums[k].l > 0 or r < n-1):class Solution:
def maximumScore(self, nums: List[int], k: int) -> int:
l = r = k
res = nums[k]
cur_min = nums[k]
while l > 0 or r < len(nums) - 1:
left = nums[l - 1] if l > 0 else 0
right = nums[r + 1] if r < len(nums) - 1 else 0
if left > right:
l -= 1
cur_min = min(cur_min, left)
else:
r += 1
cur_min = min(cur_min, right)
res = max(res, cur_min * (r - l + 1))
return resThe problem requires the subarray to contain index k. A common mistake is computing the maximum score over all subarrays without enforcing this constraint. In the monotonic stack approach, you must check that the range [left, right] actually contains k before updating the result. Skipping this check leads to incorrect answers when the global maximum rectangle doesn't include k.
When computing the left and right boundaries of a valid subarray, it's easy to be off by one. The valid range for an element at index i extends from prev_smaller + 1 to next_smaller - 1, not from prev_smaller to next_smaller. Miscalculating these boundaries causes incorrect subarray lengths and wrong scores.
In the greedy two-pointer approach, you should always expand toward the larger neighbor to maintain the highest possible minimum for as long as possible. Expanding toward the smaller neighbor prematurely reduces the minimum value, potentially missing the optimal score. Always compare nums[l-1] with nums[r+1] and expand toward the larger one.
When the left pointer reaches 0 or the right pointer reaches n-1, you can only expand in one direction. Failing to handle these boundary conditions (e.g., accessing nums[-1] or nums[n]) causes index out of bounds errors. Use sentinel values or explicit boundary checks to handle these cases gracefully.
The score is min(subarray) * length(subarray), not min(subarray) * sum(subarray). Confusing this formula with similar problems leads to computing the wrong value entirely. Always verify you're multiplying the minimum element by the subarray length, not its sum.