You are given an integer array nums and a positive integer k. Return the sum of the maximum and minimum elements of all subarrays with at mostk elements.
Β
Example 1:
Input:nums = [1,2,3], k = 2
Output:20
Explanation:
The subarrays of nums with at most 2 elements are:
Subarray
Minimum
Maximum
Sum
[1]
1
1
2
[2]
2
2
4
[3]
3
3
6
[1, 2]
1
2
3
[2, 3]
2
3
5
Final Total
Β
Β
20
The output would be 20.
Example 2:
Input:nums = [1,-3,1], k = 2
Output:-6
Explanation:
The subarrays of nums with at most 2 elements are:
Subarray
Minimum
Maximum
Sum
[1]
1
1
2
[-3]
-3
-3
-6
[1]
1
1
2
[1, -3]
-3
1
-2
[-3, 1]
-3
1
-2
Final Total
Β
Β
-6
The output would be -6.
Β
Constraints:
1 <= nums.length <= 80000
1 <= k <= nums.length
-106 <= nums[i] <= 106
Solutions
Solution 1: Monotonic Deques for Maximums and Minimums
The goal is to calculate total sum \(S = \sum_i (\text{MaxSum}_i + \text{MinSum}_i)\), where:
\(\text{MaxSum}_i\): sum of maximum values of all valid subarrays ending at index \(i\).
\(\text{MinSum}_i\): sum of minimum values of all valid subarrays ending at index \(i\).
We maintain two Deques, used as monotonic stacks with boundary control: max_stack and min_stack.
These track maximum and minimum values for all subarrays ending at index \(i\) with a length not exceeding \(k\).
Each element in deques is a triplet: [index, value, count], where count represents how many times this value acts as the max/min within current window.
Step 1: Boundary Control
For each element \(nums[i]\), check if window boundary \(\max(0, i - k + 1)\) has advanced.
If \(i - k \ge 0\), it means the subarray \(nums[i-k \dots i]\) would exceed length \(k\) due to inclusion of \(nums[i]\).
Contribution of the subarray starting at \(i-k\) must be removed. This contribution is located at the front of our deques.
We decrement the count of deques' front. If the front element's index falls out of window range, we popleft() to maintain efficiency.
Step 2: Monotonicity
Taking max_stack as an example:
While max_stack is not empty and max_stack top value \(\leq nums[i]\) (1):
Current \(nums[i]\) will replace this top element as the new maximum for all subarrays this top element previously "served."
We take over the prev_shares (which is the count) from this popped element.
Net increase to subarrays_max_sum is calculated as \((nums[i] - prev\_num) \times prev\_shares\).
After while-loop, we add \(nums[i]\)'s own contribution, as a single-element subarray, to subarrays_max_sum, and push \(nums[i]\) onto max_stack with its cumulative count and index.
Logic for min_stack processing is similar, but inequality (1) must change into min_stack top value \(\geq nums[i]\).
Step 3: Accumulation
At the end of each iteration \(i\), we add current subarrays_max_sum and subarrays_min_sum to global total subarrays_max_min_sum.
Complexity Analysis
Time Complexity:\(O(n)\), where \(n\) is length of \(nums\). Each element is pushed and popped at most 4 times in total among two deques.
Space Complexity:\(O(n)\) to store deques and state variables.
classSolution:defminMaxSubarraySum(self,nums:list[int],k:int)->int:subarrays_max_min_sum=0max_stack:deque[list[int]]=deque([])# Format: [idx, num, shares].subarrays_max_sum=0min_stack:deque[list[int]]=deque([])# Format: [idx, num, shares].subarrays_min_sum=0forend_idx,numinenumerate(nums):start_idx=max(0,end_idx-k+1)# Window start idx slides by 1: must update stacks' info.ifstart_idx>0:max_stack[0][2]-=1# Decrement stack's front num shares.subarrays_max_sum-=max_stack[0][1]ifmax_stack[0][0]<start_idx:# Front num out of window.max_stack.popleft()min_stack[0][2]-=1# Decrement stack's front num shares.subarrays_min_sum-=min_stack[0][1]ifmin_stack[0][0]<start_idx:# Front num out of window.min_stack.popleft()max_shares=1# Base case.subarrays_max_sum+=numwhilemax_stackandmax_stack[-1][1]<=num:_,prev_num,prev_shares=max_stack.pop()max_shares+=prev_shares# Max shares transition.# Reflect transition in max sum.subarrays_max_sum+=(num-prev_num)*prev_sharesmax_stack.append([end_idx,num,max_shares])min_shares=1# Base case.subarrays_min_sum+=numwhilemin_stackandmin_stack[-1][1]>=num:_,prev_num,prev_shares=min_stack.pop()min_shares+=prev_shares# Min shares transition.# Reflect transition in min sum.subarrays_min_sum+=(num-prev_num)*prev_sharesmin_stack.append([end_idx,num,min_shares])subarrays_max_min_sum+=subarrays_max_sum+subarrays_min_sumreturnsubarrays_max_min_sum
classSolution{public:longlongminMaxSubarraySum(vector<int>&nums,intk){longlongtotalMaxMinSum=0;longlongwindowMaxSum=0,windowMinSum=0;// Format: {idx, num, shares}. Use long long to prevent overflow.deque<tuple<int,int,longlong>>maxStack,minStack;for(intendIdx=0;endIdx<nums.size();endIdx++){intstartIdx=max(0,endIdx-k+1);// Window start idx slides by 1: must update stacks' info.if(startIdx>0){get<2>(maxStack.front())--;// Decrement stack's front num shares.windowMaxSum-=get<1>(maxStack.front());// Front num out of window.if(get<0>(maxStack.front())<startIdx)maxStack.pop_front();get<2>(minStack.front())--;// Decrement stack's front num shares.windowMinSum-=get<1>(minStack.front());// Front num out of window.if(get<0>(minStack.front())<startIdx)minStack.pop_front();}longlongnum=nums[endIdx];longlongmaxShares=1;// Base case.windowMaxSum+=num;while(!maxStack.empty()&&get<1>(maxStack.back())<=num){intprevNum=get<1>(maxStack.back());longlongprevShares=get<2>(maxStack.back());maxStack.pop_back();maxShares+=prevShares;// Max shares transition.// Reflect transition in max sum.windowMaxSum+=(num-prevNum)*prevShares;}maxStack.push_back({endIdx,num,maxShares});longlongminShares=1;// Base case.windowMinSum+=num;while(!minStack.empty()&&get<1>(minStack.back())>=num){intprevNum=get<1>(minStack.back());longlongprevShares=get<2>(minStack.back());minStack.pop_back();minShares+=prevShares;// Min shares transition.// Reflect transition in min sum.windowMinSum+=(num-prevNum)*prevShares;}minStack.push_back({endIdx,num,minShares});totalMaxMinSum+=windowMaxSum+windowMinSum;}returntotalMaxMinSum;}};