Skip to content
dsa450for five year olds

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

array
01234555 > 51, length 314456019

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.

java
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.

  1. Move end right one step at a time and add arr[end] to the sum.
  2. While the sum is greater than x: write down the length end - start + 1 if it is the best so far, then remove arr[start] and move start right.
  3. 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

array
012345window14456019endstart

end = 0. Add 1. The window holds 1 coin. Not more than 51.

sum
1
best
none
  • answer
  • path
  • just added
  • ignored
java
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. Keep sum in a long.

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 than prefix[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.