Off-by-one on range boundaries
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Break down a hard problem into reliable checkpoints, edge-case handling, and complexity trade-offs.
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 most k 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 <= 800001 <= k <= nums.length-106 <= nums[i] <= 106Problem summary: 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 most k elements.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array · Math · Stack
[1,2,3] 2
[1,-3,1] 2
next-greater-element-ii)Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #3430: Maximum and Minimum Sums of at Most Size K Subarrays
class Solution {
// Similar to 2104. Sum of Subarray Ranges
public long minMaxSubarraySum(int[] nums, int k) {
Pair<int[], int[]> gt = getPrevNext(nums, (a, b) -> a < b);
Pair<int[], int[]> lt = getPrevNext(nums, (a, b) -> a > b);
int[] prevGt = gt.getKey();
int[] nextGt = gt.getValue();
int[] prevLt = lt.getKey();
int[] nextLt = lt.getValue();
return subarraySum(nums, k, prevGt, nextGt) + subarraySum(nums, k, prevLt, nextLt);
}
// Returns the sum of all subarrays with a size <= k, The `prev` and `next`
// arrays are used to store the indices of the nearest numbers that are
// smaller or larger than the current number, respectively.
private long subarraySum(int[] nums, int k, int[] prev, int[] next) {
long res = 0;
for (int i = 0; i < nums.length; ++i) {
final int l = Math.min(i - prev[i], k);
final int r = Math.min(next[i] - i, k);
final int extra = Math.max(0, l + r - 1 - k);
res += (long) nums[i] * (l * r - extra * (extra + 1) / 2);
}
return res;
}
// Returns `prev` and `next`, that store the indices of the nearest numbers
// that are smaller or larger than the current number depending on `op`.
private Pair<int[], int[]> getPrevNext(int[] nums, BiFunction<Integer, Integer, Boolean> op) {
final int n = nums.length;
int[] prev = new int[n];
int[] next = new int[n];
Arrays.fill(prev, -1);
Arrays.fill(next, n);
Deque<Integer> stack = new ArrayDeque<>();
for (int i = 0; i < n; ++i) {
while (!stack.isEmpty() && op.apply(nums[stack.peek()], nums[i]))
next[stack.pop()] = i;
if (!stack.isEmpty())
prev[i] = stack.peek();
stack.push(i);
}
return new Pair<>(prev, next);
}
}
// Accepted solution for LeetCode #3430: Maximum and Minimum Sums of at Most Size K Subarrays
package main
import "math"
// https://space.bilibili.com/206214
func minMaxSubarraySum(nums []int, k int) int64 {
count := func(m int) int {
if m <= k {
return (m + 1) * m / 2
}
return (m*2 - k + 1) * k / 2
}
// 计算最小值的贡献
sumSubarrayMins := func() (res int) {
st := []int{-1} // 哨兵
for r, x := range nums {
for len(st) > 1 && nums[st[len(st)-1]] >= x {
i := st[len(st)-1]
st = st[:len(st)-1]
l := st[len(st)-1]
cnt := count(r-l-1) - count(i-l-1) - count(r-i-1)
res += nums[i] * cnt // 累加贡献
}
st = append(st, r)
}
return
}
nums = append(nums, math.MinInt)
ans := sumSubarrayMins()
// 所有元素取反(求最大值),就可以复用同一份代码了
for i := range nums {
nums[i] = -nums[i]
}
ans -= sumSubarrayMins()
return int64(ans)
}
func minMaxSubarraySum1(nums []int, k int) int64 {
// 计算最小值的贡献
sumSubarrayMins := func() (res int) {
n := len(nums)
// 左边界 left[i] 为左侧严格小于 nums[i] 的最近元素位置(不存在时为 -1)
left := make([]int, n)
// 右边界 right[i] 为右侧小于等于 nums[i] 的最近元素位置(不存在时为 n)
right := make([]int, n)
st := []int{-1} // 哨兵,方便赋值 left
for i, x := range nums {
for len(st) > 1 && x <= nums[st[len(st)-1]] {
right[st[len(st)-1]] = i // i 是栈顶的右边界
st = st[:len(st)-1]
}
left[i] = st[len(st)-1]
st = append(st, i)
}
for _, i := range st[1:] {
right[i] = n
}
for i, x := range nums {
l, r := left[i], right[i]
if r-l-1 <= k {
cnt := (i - left[i]) * (right[i] - i)
res += x * cnt // 累加贡献
} else {
l = max(l, i-k)
r = min(r, i+k)
// 左端点 > r-k 的子数组个数
cnt := (r - i) * (i - (r - k))
// 左端点 <= r-k 的子数组个数
cnt2 := (l + r + k - i*2 + 1) * (r - l - k) / 2
res += x * (cnt + cnt2) // 累加贡献
}
}
return
}
ans := sumSubarrayMins()
// 所有元素取反(求最大值),就可以复用同一份代码了
for i := range nums {
nums[i] = -nums[i]
}
ans -= sumSubarrayMins()
return int64(ans)
}
# Accepted solution for LeetCode #3430: Maximum and Minimum Sums of at Most Size K Subarrays
class Solution:
# Similar to 2104. Sum of Subarray Ranges
def minMaxSubarraySum(self, nums: list[int], k: int) -> int:
prevGt, nextGt = self._getPrevNext(nums, operator.lt)
prevLt, nextLt = self._getPrevNext(nums, operator.gt)
return (self._subarraySum(nums, prevGt, nextGt, k) +
self._subarraySum(nums, prevLt, nextLt, k))
def _subarraySum(
self,
nums: list[int],
prev: list[int],
next: list[int],
k: int
) -> int:
"""
Returns the sum of all subarrays with a size <= k, The `prev` and `next`
arrays are used to store the indices of the nearest numbers that are
smaller or larger than the current number, respectively.
"""
res = 0
for i, num in enumerate(nums):
l = min(i - prev[i], k)
r = min(next[i] - i, k)
extra = max(0, l + r - 1 - k)
res += num * (l * r - extra * (extra + 1) // 2)
return res
def _getPrevNext(
self,
nums: list[int],
op: callable
) -> tuple[list[int], list[int]]:
"""
Returns `prev` and `next`, that store the indices of the nearest numbers
that are smaller or larger than the current number depending on `op`.
"""
n = len(nums)
prev = [-1] * n
next = [n] * n
stack = []
for i, num in enumerate(nums):
while stack and op(nums[stack[-1]], num):
index = stack.pop()
next[index] = i
if stack:
prev[i] = stack[-1]
stack.append(i)
return prev, next
// Accepted solution for LeetCode #3430: Maximum and Minimum Sums of at Most Size K Subarrays
// Rust example auto-generated from java reference.
// Replace the signature and local types with the exact LeetCode harness for this problem.
impl Solution {
pub fn rust_example() {
// Port the logic from the reference block below.
}
}
// Reference (java):
// // Accepted solution for LeetCode #3430: Maximum and Minimum Sums of at Most Size K Subarrays
// class Solution {
// // Similar to 2104. Sum of Subarray Ranges
// public long minMaxSubarraySum(int[] nums, int k) {
// Pair<int[], int[]> gt = getPrevNext(nums, (a, b) -> a < b);
// Pair<int[], int[]> lt = getPrevNext(nums, (a, b) -> a > b);
// int[] prevGt = gt.getKey();
// int[] nextGt = gt.getValue();
// int[] prevLt = lt.getKey();
// int[] nextLt = lt.getValue();
// return subarraySum(nums, k, prevGt, nextGt) + subarraySum(nums, k, prevLt, nextLt);
// }
//
// // Returns the sum of all subarrays with a size <= k, The `prev` and `next`
// // arrays are used to store the indices of the nearest numbers that are
// // smaller or larger than the current number, respectively.
// private long subarraySum(int[] nums, int k, int[] prev, int[] next) {
// long res = 0;
// for (int i = 0; i < nums.length; ++i) {
// final int l = Math.min(i - prev[i], k);
// final int r = Math.min(next[i] - i, k);
// final int extra = Math.max(0, l + r - 1 - k);
// res += (long) nums[i] * (l * r - extra * (extra + 1) / 2);
// }
// return res;
// }
//
// // Returns `prev` and `next`, that store the indices of the nearest numbers
// // that are smaller or larger than the current number depending on `op`.
// private Pair<int[], int[]> getPrevNext(int[] nums, BiFunction<Integer, Integer, Boolean> op) {
// final int n = nums.length;
// int[] prev = new int[n];
// int[] next = new int[n];
// Arrays.fill(prev, -1);
// Arrays.fill(next, n);
// Deque<Integer> stack = new ArrayDeque<>();
// for (int i = 0; i < n; ++i) {
// while (!stack.isEmpty() && op.apply(nums[stack.peek()], nums[i]))
// next[stack.pop()] = i;
// if (!stack.isEmpty())
// prev[i] = stack.peek();
// stack.push(i);
// }
// return new Pair<>(prev, next);
// }
// }
// Accepted solution for LeetCode #3430: Maximum and Minimum Sums of at Most Size K Subarrays
// Auto-generated TypeScript example from java.
function exampleSolution(): void {
}
// Reference (java):
// // Accepted solution for LeetCode #3430: Maximum and Minimum Sums of at Most Size K Subarrays
// class Solution {
// // Similar to 2104. Sum of Subarray Ranges
// public long minMaxSubarraySum(int[] nums, int k) {
// Pair<int[], int[]> gt = getPrevNext(nums, (a, b) -> a < b);
// Pair<int[], int[]> lt = getPrevNext(nums, (a, b) -> a > b);
// int[] prevGt = gt.getKey();
// int[] nextGt = gt.getValue();
// int[] prevLt = lt.getKey();
// int[] nextLt = lt.getValue();
// return subarraySum(nums, k, prevGt, nextGt) + subarraySum(nums, k, prevLt, nextLt);
// }
//
// // Returns the sum of all subarrays with a size <= k, The `prev` and `next`
// // arrays are used to store the indices of the nearest numbers that are
// // smaller or larger than the current number, respectively.
// private long subarraySum(int[] nums, int k, int[] prev, int[] next) {
// long res = 0;
// for (int i = 0; i < nums.length; ++i) {
// final int l = Math.min(i - prev[i], k);
// final int r = Math.min(next[i] - i, k);
// final int extra = Math.max(0, l + r - 1 - k);
// res += (long) nums[i] * (l * r - extra * (extra + 1) / 2);
// }
// return res;
// }
//
// // Returns `prev` and `next`, that store the indices of the nearest numbers
// // that are smaller or larger than the current number depending on `op`.
// private Pair<int[], int[]> getPrevNext(int[] nums, BiFunction<Integer, Integer, Boolean> op) {
// final int n = nums.length;
// int[] prev = new int[n];
// int[] next = new int[n];
// Arrays.fill(prev, -1);
// Arrays.fill(next, n);
// Deque<Integer> stack = new ArrayDeque<>();
// for (int i = 0; i < n; ++i) {
// while (!stack.isEmpty() && op.apply(nums[stack.peek()], nums[i]))
// next[stack.pop()] = i;
// if (!stack.isEmpty())
// prev[i] = stack.peek();
// stack.push(i);
// }
// return new Pair<>(prev, next);
// }
// }
Use this to step through a reusable interview workflow for this problem.
For each element, scan left (or right) to find the next greater/smaller element. The inner scan can visit up to n elements per outer iteration, giving O(n²) total comparisons. No extra space needed beyond loop variables.
Each element is pushed onto the stack at most once and popped at most once, giving 2n total operations = O(n). The stack itself holds at most n elements in the worst case. The key insight: amortized O(1) per element despite the inner while-loop.
Review these before coding to avoid predictable interview regressions.
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Wrong move: Temporary multiplications exceed integer bounds.
Usually fails on: Large inputs wrap around unexpectedly.
Fix: Use wider types, modular arithmetic, or rearranged operations.
Wrong move: Pushing without popping stale elements invalidates next-greater/next-smaller logic.
Usually fails on: Indices point to blocked elements and outputs shift.
Fix: Pop while invariant is violated before pushing current element.