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.



