Shortest Subarray With Sum at Least K: A Monotonic Stack + Binary Search Approach

Revision en2, by dtu1141b, 2026-07-28 23:29:22

Shortest Subarray With Sum at Least

Unable to parse markup [type=CF_MATHJAX]

$: An

Unable to parse markup [type=CF_MATHJAX]

$ Solution Using a Monotonic Stack and Binary Search

The standard solution uses a monotonic deque and runs in

Unable to parse markup [type=CF_MATHJAX]

$.

This post describes an alternative

Unable to parse markup [type=CF_MATHJAX]

$ approach. We maintain the useful prefix sums in a monotonic vector and binary search over it.

The idea follows from two observations:

  • A smaller prefix sum is better.
  • Among feasible prefix sums, a later index is better.

Prefix-sum formulation

Let

Unable to parse markup [type=CF_MATHJAX]

$

The sum of the subarray from

Unable to parse markup [type=CF_MATHJAX]

$ to

Unable to parse markup [type=CF_MATHJAX]

$ is

Unable to parse markup [type=CF_MATHJAX]

$

We require

Unable to parse markup [type=CF_MATHJAX]

$

or equivalently,

Unable to parse markup [type=CF_MATHJAX]

$

Thus, for every right endpoint

Unable to parse markup [type=CF_MATHJAX]

$, we need the largest index

Unable to parse markup [type=CF_MATHJAX]

$ satisfying

Unable to parse markup [type=CF_MATHJAX]

$

Choosing the largest valid

Unable to parse markup [type=CF_MATHJAX]

$ minimizes the length

Unable to parse markup [type=CF_MATHJAX]

$.


Removing dominated prefix sums

Suppose

Unable to parse markup [type=CF_MATHJAX]

$

and

Unable to parse markup [type=CF_MATHJAX]

$

Then prefix index

Unable to parse markup [type=CF_MATHJAX]

$ is never useful again.

For any future endpoint

Unable to parse markup [type=CF_MATHJAX]

$, if

Unable to parse markup [type=CF_MATHJAX]

$

then, because

Unable to parse markup [type=CF_MATHJAX]

$,

Unable to parse markup [type=CF_MATHJAX]

$

Moreover,

Unable to parse markup [type=CF_MATHJAX]

$

Therefore, whenever

Unable to parse markup [type=CF_MATHJAX]

$ is valid,

Unable to parse markup [type=CF_MATHJAX]

$ is also valid and gives a shorter subarray.

Hence, when a new prefix sum arrives, every previous prefix sum greater than or equal to it can be removed permanently.

while (!a.empty() && a.back().first >= p[i]) {
    a.pop_back();
}
a.push_back({p[i], i});

After every insertion, the stored pairs satisfy

Unable to parse markup [type=CF_MATHJAX]

$

and

Unable to parse markup [type=CF_MATHJAX]

$

Thus, the vector is increasing in both prefix sum and index.


Binary search

For the current endpoint

Unable to parse markup [type=CF_MATHJAX]

$, define

Unable to parse markup [type=CF_MATHJAX]

$

We need the last stored pair whose prefix sum is at most

Unable to parse markup [type=CF_MATHJAX]

$.

Since the prefix sums are increasing, all valid pairs form a prefix of the vector.

Since the indices are also increasing, the last valid pair has the largest valid index.

Therefore, we use

int pos = upper_bound(
    a.begin(),
    a.end(),
    make_pair(p[i] - k, i)
) - a.begin() - 1;

Searching for

Unable to parse markup [type=CF_MATHJAX]

$

finds the last stored pair satisfying

Unable to parse markup [type=CF_MATHJAX]

$


Correctness proof

Lemma 1

If

Unable to parse markup [type=CF_MATHJAX]

$ and

Unable to parse markup [type=CF_MATHJAX]

$, then prefix index

Unable to parse markup [type=CF_MATHJAX]

$ can be removed permanently after processing

Unable to parse markup [type=CF_MATHJAX]

$.

Proof

Whenever

Unable to parse markup [type=CF_MATHJAX]

$ forms a valid subarray with a future endpoint

Unable to parse markup [type=CF_MATHJAX]

$, we have

Unable to parse markup [type=CF_MATHJAX]

$

Since

Unable to parse markup [type=CF_MATHJAX]

$,

Unable to parse markup [type=CF_MATHJAX]

$

Thus,

Unable to parse markup [type=CF_MATHJAX]

$ is also valid. Since

Unable to parse markup [type=CF_MATHJAX]

$,

Unable to parse markup [type=CF_MATHJAX]

$

Therefore,

Unable to parse markup [type=CF_MATHJAX]

$ always gives a shorter subarray than

Unable to parse markup [type=CF_MATHJAX]

$. Hence

Unable to parse markup [type=CF_MATHJAX]

$ can never be optimal again.

Unable to parse markup [type=CF_MATHJAX]

$

Lemma 2

The maintained vector is strictly increasing in both prefix sums and indices.

Proof

Indices are inserted from left to right, so their order is increasing.

Before inserting

Unable to parse markup [type=CF_MATHJAX]

$, every suffix element whose prefix sum is at least

Unable to parse markup [type=CF_MATHJAX]

$ is removed. Therefore, the prefix sums also remain strictly increasing.

Unable to parse markup [type=CF_MATHJAX]

$

Theorem

For every endpoint

Unable to parse markup [type=CF_MATHJAX]

$, binary search returns the shortest valid subarray ending at

Unable to parse markup [type=CF_MATHJAX]

$.

Proof

All stored prefix sums satisfying

Unable to parse markup [type=CF_MATHJAX]

$

form a prefix of the vector.

Binary search returns the final element of this prefix. Since the indices are increasing, this element has the largest valid index and therefore minimizes

Unable to parse markup [type=CF_MATHJAX]

$.

Any removed prefix was dominated by a later prefix according to Lemma 1, so removing it cannot destroy an optimal answer.

Taking the minimum over all endpoints gives the globally shortest valid subarray.

Unable to parse markup [type=CF_MATHJAX]

$


Implementation

for (int i = 0; i <= n; i++) {
    while (!a.empty() && a.back().first >= p[i]) {
        a.pop_back();
    }

    a.push_back({p[i], i});

    if (i == 0) continue;

    int pos = upper_bound(
        a.begin(),
        a.end(),
        make_pair(p[i] - k, i)
    ) - a.begin() - 1;

    if (pos == -1) continue;

    ans = min(ans, i - a[pos].second);
}

Here, p is the prefix-sum array, while a stores the non-dominated pairs

Unable to parse markup [type=CF_MATHJAX]

$

Since the original problem has

Unable to parse markup [type=CF_MATHJAX]

$, inserting

Unable to parse markup [type=CF_MATHJAX]

$ before querying cannot create a zero-length subarray, because

Unable to parse markup [type=CF_MATHJAX]

$


Complexity

Each prefix sum is inserted once and removed at most once. Therefore, all stack operations together take

Unable to parse markup [type=CF_MATHJAX]

$.

We perform one binary search for every prefix sum, so the total running time is

Unable to parse markup [type=CF_MATHJAX]

$

The memory complexity is

Unable to parse markup [type=CF_MATHJAX]

$


Final perspective

The important object is not really a stack or deque. It is the set of non-dominated prefix states.

A state

Unable to parse markup [type=CF_MATHJAX]

$

is dominated by

Unable to parse markup [type=CF_MATHJAX]

$

whenever

Unable to parse markup [type=CF_MATHJAX]

$

and

Unable to parse markup [type=CF_MATHJAX]

$

The second state is simultaneously:

  • easier to satisfy, because its prefix sum is smaller;
  • better for minimizing the answer, because its index is later.

Maintaining only non-dominated states creates a monotone frontier increasing in both prefix sum and index.

The classical deque solution exploits the same dominance relation to obtain

Unable to parse markup [type=CF_MATHJAX]

$. This approach instead uses binary search over the monotone frontier, giving a clean

Unable to parse markup [type=CF_MATHJAX]

$ solution.

Tags stack, binary search, monotonic stack

History

 
 
 
 
Revisions
 
 
  Rev. Lang. By When Δ Comment
en4 English dtu1141b 2026-07-28 23:36:55 0 Tiny change: '\nThe standa' -> 'The standa'
en3 English dtu1141b 2026-07-28 23:35:09 1661 Tiny change: 'i], i});\n````\n\nAfter ' -> 'i], i});\n\nAfter ' (published)
en2 English dtu1141b 2026-07-28 23:29:22 2264
en1 English dtu1141b 2026-07-28 23:24:39 5384 Initial revision (saved to drafts)