Array · 21 of 36
Smallest Subarray with sum greater than a given value
Find the shortest run of piggy banks in a row whose coins add up to more than a target, by stretching and shrinking a window over the row.
- Simple way
- time O(n^2)
room O(1) - Clever way
- time O(n)
room O(1)
The problem, simply
You get an array of non-negative numbers and a number x. Find the shortest stretch of numbers next to each other whose sum is strictly greater than x. Give back its length.
If no stretch has a sum greater than x, give back 0.
A story to remember it
Picture it
Six piggy banks, target more than 51. The banks 4, 45, 6 hold 55 coins, which is more than 51, and no run of 1 or 2 banks gets there.
- answer
Examples
A normal case
- In
arr = [1, 4, 45, 6, 0, 19], x = 51- Out
3
4 + 45 + 6 = 55, which is more than 51.
One number is enough
- In
arr = [1, 10, 5, 2, 7], x = 9- Out
1
10 alone is more than 9.
A longer run
- In
arr = [1, 11, 100, 1, 0, 200, 3, 2, 1, 250], x = 280- Out
4
100 + 1 + 0 + 200 = 301. No run of 3 gets above 280.
Exactly equal is not enough
- In
arr = [2, 3, 5], x = 10- Out
0
The whole array adds up to 10, which is not greater than 10. So there is no answer.
Never enough
- In
arr = [1, 2, 4], x = 8- Out
0
Everything together is only 7.
Way 1: the simple way
Try every start. From each start, add numbers to the right until the sum passes x. That is the shortest run from this start, so stop there and move to the next start.
class Solution {
public int smallestSubWithSum(int[] arr, int x) {
int n = arr.length, best = Integer.MAX_VALUE;
for (int i = 0; i < n; i++) {
long sum = 0;
for (int j = i; j < n; j++) {
sum += arr[j];
if (sum > x) { // the first time it passes x
best = Math.min(best, j - i + 1);
break; // longer runs from i are worse
}
}
}
return best == Integer.MAX_VALUE ? 0 : best;
}
}How long it takes: up to n starts, each walking up to n steps, O(n^2). Extra room: a few numbers, O(1).
Way 2: the clever way
Keep a window [start, end] and its sum.
- Move
endright one step at a time and addarr[end]to the sum. - While the sum is greater than
x: write down the lengthend - start + 1if it is the best so far, then removearr[start]and movestartright. - At the end, return the best length, or 0 if nothing was written down.
Each number joins the window once and leaves once. That is why this is fast.
Stretch on the right, squeeze on the left
01 / 10
end = 0. Add 1. The window holds 1 coin. Not more than 51.
- sum
- 1
- best
- none
- answer
- path
- just added
- ignored
class Solution {
public int smallestSubWithSum(int[] arr, int x) {
int best = Integer.MAX_VALUE, start = 0;
long sum = 0;
for (int end = 0; end < arr.length; end++) {
sum += arr[end]; // stretch on the right
while (sum > x) { // more than enough: squeeze on the left
best = Math.min(best, end - start + 1);
sum -= arr[start];
start++;
}
}
return best == Integer.MAX_VALUE ? 0 : best;
}
}How long it takes: end moves n times and start moves at most n times in total, O(n). Extra room: a few numbers, O(1).
Watch out for
- Return 0 when nothing works. Do not return
Integer.MAX_VALUE. - The window trick needs non-negative numbers. With a negative number, dropping from the left could raise the sum, and the squeeze logic breaks.
- Sums of many big numbers can overflow an
int. Keepsumin along.
What interviewers ask next
- What if the array can have negative numbers (LeetCode 862)? Use prefix sums and a deque that keeps prefix indexes in increasing order of prefix value.
O(n). - A different
O(n log n)way for non-negative numbers: build prefix sums, which only go up, and for each start binary search the first end whose prefix is more thanprefix[start] + x. - Longest stretch with sum at most
x. Same window, but now you record the length while the sum is small enough. - Count stretches with sum exactly
k. With negatives allowed, use a hash map of prefix sums and how often each appeared.
Remember this
Grown-up words: the frame is a variable-size sliding window, a stretch of numbers next to each other is a subarray, and the stretch and squeeze moves are the two pointers of the window.