Stacks & Queues · 35 of 38
Sum of minimum and maximum elements of all subarrays of size k
Slide a window of k boxes along a row of numbers and add up the biggest plus the smallest number seen in every window.
- Simple way
- time O(n*k)
room O(1) - Clever way
- time O(n)
room O(k)
The problem, simply
You get an array arr and a window size k. Look at every run of k boxes next to each other: boxes 0 to k - 1, then 1 to k, and so on. For each window, add its largest number and its smallest number. Give back the sum over all windows.
A story to remember it
Picture it
The four windows of size 3. The first window, 9, 1, 4, has max 9 and min 1, so it adds 10.
- answer
Examples
With negative numbers
- In
arr = [2, 5, -1, 7, -3, -1, -2], k = 4- Out
18
Windows give 7 + (-1) = 6, then 7 + (-3) = 4 three times. 6 + 4 + 4 + 4 = 18.
The animation's row
- In
arr = [9, 1, 4, 2, 6, 3], k = 3- Out
31
Windows give 9 + 1 = 10, 4 + 1 = 5, 6 + 2 = 8 and 6 + 2 = 8.
Going up
- In
arr = [1, 2, 3, 4], k = 2- Out
15
(1 + 2) + (2 + 3) + (3 + 4) = 15.
Window of one
- In
arr = [3, -1, 4], k = 1- Out
12
Each window has one number that is both the max and the min, so each counts twice: 6 - 2 + 8 = 12.
All the same
- In
arr = [4, 4, 4], k = 2- Out
16
Two windows, each 4 + 4.
Way 1: the simple way
For each window, walk through its k numbers and find the max and the min.
- For each start
ifrom0ton - k: - Scan
arr[i]toarr[i + k - 1], keeping the max and the min. - Add
max + minto the total.
Way 1 scans each window from scratch. For the second window it looks at 1, 4, 2 again, even though two of them were just seen.
- checking
class Solution {
public long sumMinMax(int[] arr, int k) {
long total = 0;
for (int i = 0; i + k <= arr.length; i++) {
int max = Integer.MIN_VALUE, min = Integer.MAX_VALUE;
for (int j = i; j < i + k; j++) { // look at the whole window again
max = Math.max(max, arr[j]);
min = Math.min(min, arr[j]);
}
total += (long) max + min;
}
return total;
}
}How long it takes: n - k + 1 windows, k numbers each, O(n*k). Extra room: a few numbers, O(1).
Way 2: the clever way
Keep two deques (lines you can use from both ends) of positions.
- The max deque keeps positions whose values go down from front to back. Its front is the max of the window.
- The min deque keeps positions whose values go up from front to back. Its front is the min of the window.
For each new position i:
- If a front position has slid out of the window (it is
i - kor less), remove it from the front. - From the back of the max deque, remove every position whose value is not bigger than
arr[i]. They can never be the max again. Do the same on the min deque for values not smaller. - Add
iat the back of both deques. - Once the first window is full (
i >= k - 1), add the two front values to the total.
Two deques keep the window max and min ready at the front
01 / 08
Windows have size 3. The max deque keeps candidates for the biggest, going down from front to back. The min deque keeps candidates for the smallest, going up.
- k
- 3
- total
- 0
- looking now
- answer
- just added
import java.util.*;
class Solution {
public long sumMinMax(int[] arr, int k) {
Deque<Integer> maxQ = new ArrayDeque<>(); // positions, values going down
Deque<Integer> minQ = new ArrayDeque<>(); // positions, values going up
long total = 0;
for (int i = 0; i < arr.length; i++) {
if (!maxQ.isEmpty() && maxQ.peekFirst() <= i - k) maxQ.pollFirst(); // slid out
if (!minQ.isEmpty() && minQ.peekFirst() <= i - k) minQ.pollFirst();
while (!maxQ.isEmpty() && arr[maxQ.peekLast()] <= arr[i]) maxQ.pollLast();
while (!minQ.isEmpty() && arr[minQ.peekLast()] >= arr[i]) minQ.pollLast();
maxQ.addLast(i);
minQ.addLast(i);
if (i >= k - 1) {
total += (long) arr[maxQ.peekFirst()] + arr[minQ.peekFirst()];
}
}
return total;
}
}How long it takes: each position joins each deque once and leaves at most once, so O(n) in total. Extra room: each deque holds positions from one window only, O(k).
Watch out for
- Removing old fronts with
ifis enough here, because the window moves one step at a time, so at most one position expires per step. Awhileis also fine and is safer if you are unsure. - Overflow. The sum of many windows can pass the
intlimit. Return along. kbigger than the array means no window at all. The loop adds nothing and returns 0; check what the interviewer wants.
What interviewers ask next
- Sliding window maximum (LeetCode 239): the same max deque, but output the front for each window instead of adding.
- Longest subarray where max minus min is at most a limit: use both deques with a window that grows and shrinks,
O(n). - First negative number in every window of size
k: a single queue of positions of negative numbers. - Could a heap do it? Yes, a max heap and a min heap with lazy removal of old positions give
O(n log k). The deques are faster and simpler. - Sum of max minus min over all subarrays of every size: count for each number how many subarrays it is the max of, and how many it is the min of, using next greater and next smaller elements.
O(n).
Remember this
Grown-up words: the sliding photo frame is a sliding window, the lists you can change at both ends are deques, keeping them sorted by crossing off useless entries makes them monotonic deques, and "each item joins and leaves once" is amortized O(1) per step.