You are given an array of integers nums(0-indexed) and an integer k.
The score of a subarray (i, j) is defined as min(nums[i], nums[i+1], ..., nums[j]) * (j - i + 1). A good subarray is a subarray where i <= k <= j.
Return the maximum possible score of a good subarray.
Β
Example 1:
Input: nums = [1,4,3,7,4,5], k = 3
Output: 15
Explanation: The optimal subarray is (1, 5) with a score of min(4,3,7,4,5) * (5-1+1) = 3 * 5 = 15.
Example 2:
Input: nums = [5,5,4,5,4,1,1,1], k = 0
Output: 20
Explanation: The optimal subarray is (0, 4) with a score of min(5,5,4,5,4) * (4-0+1) = 4 * 5 = 20.
Β
Constraints:
1 <= nums.length <= 105
1 <= nums[i] <= 2 * 104
0 <= k < nums.length
Solutions
Solution 1: Monotonic Stack
We can enumerate each element \(nums[i]\) in \(nums\) as the minimum value of the subarray, and use a monotonic stack to find the first position \(left[i]\) on the left that is less than \(nums[i]\) and the first position \(right[i]\) on the right that is less than or equal to \(nums[i]\). Then, the score of the subarray with \(nums[i]\) as the minimum value is \(nums[i] \times (right[i] - left[i] - 1)\).
It should be noted that the answer can only be updated when the left and right boundaries \(left[i]\) and \(right[i]\) satisfy \(left[i]+1 \leq k \leq right[i]-1\).
The time complexity is \(O(n)\), and the space complexity is \(O(n)\). Here, \(n\) is the length of the array \(nums\).
We can initialize two pointers at the core index k and expand outward to the left and right. By maintaining the minimum value within current window, we can find maximum score in strict linear time.
Algorithm Steps:
Initialize left pointer i = k, right pointer j = k, and window minimum value min_num = nums[k]. Set initial maximum score max_score = nums[k].
Expand pointers while i > 0 or j < len(nums) - 1:
Direction: If left boundary can't expand (i == 0), move right pointer j++. If right boundary can't expand (j == len(nums) - 1), move left pointer i--.
If both sides are expandable, compare nums[i - 1] and nums[j + 1], and expand towards the side with a larger value (i.e., if nums[i - 1] >= nums[j + 1], decrement i; otherwise, increment j).
Update State: after each pointer movement, update current window minimum value: min_num = min(min_num, nums[i] or nums[j]).
Calculate Score: length of the current good subarray is j + 1 - i, and its score is score = min_num * (j + 1 - i). Update global maximum score: max_score = max(max_score, score).
Return max_score once the for loop terminates.
Complexity Analysis:
Time Complexity: \(O(n)\), where \(n\) is length of array nums. Each element is scanned at most once.
Space Complexity: \(O(1)\), as it only requires a constant amount of extra space for two pointers, window minimum value and global maximum score.
classSolution:defmaximumScore(self,nums:list[int],k:int)->int:max_score=nums[k]# Base case.min_num=nums[k]left_idx,right_idx=k,kwhile0<left_idxorright_idx<len(nums)-1:ifleft_idx==0:# Can only go right.right_idx+=1min_num=min(min_num,nums[right_idx])elifright_idx==len(nums)-1:# Can only go left.left_idx-=1min_num=min(min_num,nums[left_idx])else:# Can go bidirectional.ifnums[left_idx-1]>=nums[right_idx+1]:left_idx-=1min_num=min(min_num,nums[left_idx])else:right_idx+=1min_num=min(min_num,nums[right_idx])score=min_num*(right_idx+1-left_idx)max_score=max(max_score,score)returnmax_score
classSolution{public:intmaximumScore(vector<int>&nums,intk){intmaxScore=nums[k],minNum=nums[k];// Base case.intleftIdx=k,rightIdx=k;while(0<leftIdx||rightIdx<nums.size()-1){if(leftIdx==0){// Can only go right.rightIdx++;minNum=min(minNum,nums[rightIdx]);}elseif(rightIdx==nums.size()-1){// Can only go left.leftIdx--;minNum=min(minNum,nums[leftIdx]);}else{// Can go bidirectional.if(nums[leftIdx-1]>=nums[rightIdx+1]){leftIdx--;minNum=min(minNum,nums[leftIdx]);}else{rightIdx++;minNum=min(minNum,nums[rightIdx]);}}intscore=minNum*(rightIdx+1-leftIdx);maxScore=max(maxScore,score);}returnmaxScore;}};