209. Minimum Size Subarray Sum
Problem Description
You are given an array of positive integers nums
and a positive integer target
. Your task is to find the minimal length of a contiguous subarray whose sum is greater than or equal to target
.
A subarray is a contiguous part of the array. For example, if nums = [1, 2, 3, 4]
, then [2, 3]
is a subarray.
The problem asks you to:
- Find all possible contiguous subarrays of
nums
- Check which ones have a sum that is at least
target
- Return the length of the shortest such subarray
- If no subarray exists with sum ≥
target
, return0
For example:
- If
nums = [2, 3, 1, 2, 4, 3]
andtarget = 7
, the subarray[4, 3]
has sum = 7, which is the shortest subarray meeting the requirement, so the answer is2
- If
nums = [1, 1, 1, 1]
andtarget = 10
, no subarray can sum to at least 10, so the answer is0
The key constraint is that all integers in nums
are positive, which allows for certain optimization techniques in solving this problem efficiently.
Intuition
Since we're looking for the shortest subarray with sum ≥ target
, we need to efficiently check all possible subarrays. A naive approach would check every subarray by computing its sum from scratch, but this would be inefficient.
The key insight is to use prefix sums to quickly calculate any subarray sum. If we precompute s[i]
= sum of first i
elements, then the sum of subarray from index i
to j
equals s[j] - s[i]
.
For a subarray starting at position i
, we want to find the smallest position j
where s[j] - s[i] >= target
, which can be rewritten as s[j] >= s[i] + target
.
Here's where the crucial observation comes in: since all numbers in nums
are positive, the prefix sum array s
is monotonically increasing. This means s[0] ≤ s[1] ≤ s[2] ≤ ... ≤ s[n]
.
Because of this monotonic property, for each starting position i
, we can use binary search to find the smallest j
where s[j] >= s[i] + target
. Binary search works here precisely because the array is sorted.
The algorithm becomes:
- Build the prefix sum array
s
wheres[0] = 0
ands[i]
= sum of firsti
elements - For each possible starting position
i
, use binary search to find the earliest ending positionj
where the subarray sum is at leasttarget
- Track the minimum length found across all valid subarrays
This approach reduces the time complexity from O(n²) (checking all subarrays) to O(n log n) (n iterations with binary search in each).
Solution Approach
Let's walk through the implementation step by step:
Step 1: Build the Prefix Sum Array
We use Python's accumulate
function to create a prefix sum array s
:
s = list(accumulate(nums, initial=0))
This creates an array where s[i]
represents the sum of the first i
elements. The initial=0
parameter ensures s[0] = 0
, making our array have length n+1
. For example, if nums = [2, 3, 1, 2]
, then s = [0, 2, 5, 6, 8]
.
Step 2: Initialize the Answer
We set ans = n + 1
as an initial value larger than any possible valid subarray length. This helps us identify if no valid subarray exists at the end.
Step 3: Iterate Through Starting Positions
For each position i
in the prefix sum array s
, we treat it as a potential starting point of our subarray:
for i, x in enumerate(s):
Here, x
equals s[i]
, which is the cumulative sum up to position i
.
Step 4: Binary Search for Ending Position
For each starting position i
, we need to find the smallest index j
where s[j] >= s[i] + target
:
j = bisect_left(s, x + target)
The bisect_left
function performs binary search on the sorted array s
to find the leftmost position where we could insert x + target
while maintaining sorted order. This gives us the smallest j
where s[j] >= x + target
.
Step 5: Update Minimum Length
If j <= n
(meaning we found a valid ending position within the array bounds), we update our answer:
if j <= n:
ans = min(ans, j - i)
The length of the subarray from position i
to j
is j - i
.
Step 6: Return the Result
Finally, we check if we found any valid subarray:
return ans if ans <= n else 0
If ans
is still greater than n
, no valid subarray exists, so we return 0
.
Time Complexity: O(n log n) - We iterate through n+1 positions and perform binary search for each. Space Complexity: O(n) - For storing the prefix sum array.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a concrete example with nums = [2, 3, 1, 2, 4, 3]
and target = 7
.
Step 1: Build the Prefix Sum Array
Starting with nums = [2, 3, 1, 2, 4, 3]
, we create the prefix sum array:
s[0] = 0
(initial value)s[1] = 0 + 2 = 2
s[2] = 2 + 3 = 5
s[3] = 5 + 1 = 6
s[4] = 6 + 2 = 8
s[5] = 8 + 4 = 12
s[6] = 12 + 3 = 15
So s = [0, 2, 5, 6, 8, 12, 15]
Step 2: Initialize Answer
Set ans = 7
(which is n + 1, since n = 6)
Step 3-5: Iterate and Search
Now we iterate through each position in s
and use binary search:
-
i = 0,
x = s[0] = 0
:- Need to find smallest j where
s[j] >= 0 + 7 = 7
- Binary search finds j = 4 (since
s[4] = 8
is the first value ≥ 7) - Subarray length = 4 - 0 = 4
- Update:
ans = min(7, 4) = 4
- Need to find smallest j where
-
i = 1,
x = s[1] = 2
:- Need to find smallest j where
s[j] >= 2 + 7 = 9
- Binary search finds j = 5 (since
s[5] = 12
is the first value ≥ 9) - Subarray length = 5 - 1 = 4
- Update:
ans = min(4, 4) = 4
- Need to find smallest j where
-
i = 2,
x = s[2] = 5
:- Need to find smallest j where
s[j] >= 5 + 7 = 12
- Binary search finds j = 5 (since
s[5] = 12
equals 12) - Subarray length = 5 - 2 = 3
- Update:
ans = min(4, 3) = 3
- Need to find smallest j where
-
i = 3,
x = s[3] = 6
:- Need to find smallest j where
s[j] >= 6 + 7 = 13
- Binary search finds j = 6 (since
s[6] = 15
is the first value ≥ 13) - Subarray length = 6 - 3 = 3
- Update:
ans = min(3, 3) = 3
- Need to find smallest j where
-
i = 4,
x = s[4] = 8
:- Need to find smallest j where
s[j] >= 8 + 7 = 15
- Binary search finds j = 6 (since
s[6] = 15
equals 15) - Subarray length = 6 - 4 = 2
- Update:
ans = min(3, 2) = 2
- Need to find smallest j where
-
i = 5,
x = s[5] = 12
:- Need to find smallest j where
s[j] >= 12 + 7 = 19
- Binary search finds j = 7 (which is beyond array bounds)
- No valid subarray starting at position 5
- Need to find smallest j where
-
i = 6,
x = s[6] = 15
:- Need to find smallest j where
s[j] >= 15 + 7 = 22
- Binary search finds j = 7 (which is beyond array bounds)
- No valid subarray starting at position 6
- Need to find smallest j where
Step 6: Return Result
The minimum length found is 2, which corresponds to the subarray from index 4 to 5 in the original array: [4, 3]
with sum = 7.
This matches our expected answer! The subarray [4, 3]
has exactly the target sum of 7 and is the shortest possible.
Solution Implementation
1from typing import List
2from itertools import accumulate
3from bisect import bisect_left
4
5
6class Solution:
7 def minSubArrayLen(self, target: int, nums: List[int]) -> int:
8 # Get the length of the input array
9 n = len(nums)
10
11 # Create prefix sum array with initial value 0
12 # prefix_sums[i] represents sum of nums[0:i]
13 prefix_sums = list(accumulate(nums, initial=0))
14
15 # Initialize minimum length to n+1 (impossible value)
16 min_length = n + 1
17
18 # Iterate through each position in prefix sum array
19 for i, current_sum in enumerate(prefix_sums):
20 # Find the leftmost position where prefix sum >= current_sum + target
21 # This gives us the smallest j where sum(nums[i:j]) >= target
22 j = bisect_left(prefix_sums, current_sum + target)
23
24 # If valid position found (within bounds)
25 if j <= n:
26 # Update minimum length if current subarray is smaller
27 min_length = min(min_length, j - i)
28
29 # Return minimum length if found, otherwise return 0
30 return min_length if min_length <= n else 0
31
1class Solution {
2 /**
3 * Find the minimal length of a contiguous subarray whose sum is >= target.
4 * Uses prefix sum array and binary search approach.
5 *
6 * @param target the target sum to achieve or exceed
7 * @param nums the input array of positive integers
8 * @return the minimal length of subarray, or 0 if no such subarray exists
9 */
10 public int minSubArrayLen(int target, int[] nums) {
11 int n = nums.length;
12
13 // Build prefix sum array where prefixSum[i] = sum of nums[0...i-1]
14 long[] prefixSum = new long[n + 1];
15 for (int i = 0; i < n; i++) {
16 prefixSum[i + 1] = prefixSum[i] + nums[i];
17 }
18
19 // Initialize answer to impossible value (n + 1)
20 int minLength = n + 1;
21
22 // For each starting position i, find the smallest ending position j
23 // such that sum of nums[i...j-1] >= target
24 for (int i = 0; i <= n; i++) {
25 // We need prefixSum[j] - prefixSum[i] >= target
26 // So we search for the smallest j where prefixSum[j] >= prefixSum[i] + target
27 int j = binarySearchFirstGreaterOrEqual(prefixSum, prefixSum[i] + target);
28
29 // If valid position found, update minimum length
30 if (j <= n) {
31 minLength = Math.min(minLength, j - i);
32 }
33 }
34
35 // Return the result, or 0 if no valid subarray found
36 return minLength <= n ? minLength : 0;
37 }
38
39 /**
40 * Binary search to find the first index where array value >= target value.
41 *
42 * @param nums the sorted array to search in
43 * @param targetValue the value to search for
44 * @return the first index where nums[index] >= targetValue, or nums.length if not found
45 */
46 private int binarySearchFirstGreaterOrEqual(long[] nums, long targetValue) {
47 int left = 0;
48 int right = nums.length;
49
50 while (left < right) {
51 int mid = (left + right) >> 1; // Equivalent to (left + right) / 2
52
53 if (nums[mid] >= targetValue) {
54 // Mid could be the answer, search in left half including mid
55 right = mid;
56 } else {
57 // Mid is too small, search in right half excluding mid
58 left = mid + 1;
59 }
60 }
61
62 return left;
63 }
64}
65
1class Solution {
2public:
3 int minSubArrayLen(int target, vector<int>& nums) {
4 int n = nums.size();
5
6 // Build prefix sum array where prefixSum[i] = sum of nums[0...i-1]
7 // prefixSum[0] = 0 (empty prefix)
8 vector<long long> prefixSum(n + 1);
9 for (int i = 0; i < n; ++i) {
10 prefixSum[i + 1] = prefixSum[i] + nums[i];
11 }
12
13 // Initialize result to impossible value (n + 1)
14 int minLength = n + 1;
15
16 // For each starting position i, find the smallest ending position j
17 // such that sum of subarray [i, j) >= target
18 for (int i = 0; i <= n; ++i) {
19 // Find the first position j where prefixSum[j] >= prefixSum[i] + target
20 // This means sum(nums[i...j-1]) >= target
21 int j = lower_bound(prefixSum.begin(), prefixSum.end(),
22 prefixSum[i] + target) - prefixSum.begin();
23
24 // If valid position found, update minimum length
25 if (j <= n) {
26 minLength = min(minLength, j - i);
27 }
28 }
29
30 // Return the minimum length if found, otherwise return 0
31 return minLength <= n ? minLength : 0;
32 }
33};
34
1/**
2 * Finds the minimal length of a contiguous subarray with sum >= target
3 * @param target - The target sum to achieve or exceed
4 * @param nums - Array of positive integers
5 * @returns The minimal length of subarray, or 0 if no such subarray exists
6 */
7function minSubArrayLen(target: number, nums: number[]): number {
8 const arrayLength: number = nums.length;
9
10 // Build prefix sum array where prefixSum[i] = sum of nums[0...i-1]
11 const prefixSum: number[] = new Array(arrayLength + 1).fill(0);
12 for (let i = 0; i < arrayLength; i++) {
13 prefixSum[i + 1] = prefixSum[i] + nums[i];
14 }
15
16 // Initialize answer with impossible value (arrayLength + 1)
17 let minLength: number = arrayLength + 1;
18
19 /**
20 * Binary search to find the leftmost index where prefixSum[index] >= targetValue
21 * @param targetValue - The value to search for in the prefix sum array
22 * @returns The leftmost index where condition is met
23 */
24 const binarySearch = (targetValue: number): number => {
25 let left: number = 0;
26 let right: number = arrayLength + 1;
27
28 while (left < right) {
29 // Use unsigned right shift for integer division by 2
30 const mid: number = (left + right) >>> 1;
31
32 if (prefixSum[mid] >= targetValue) {
33 // Target might be at mid or to the left
34 right = mid;
35 } else {
36 // Target must be to the right
37 left = mid + 1;
38 }
39 }
40
41 return left;
42 };
43
44 // For each starting position i, find the smallest ending position j
45 // such that sum of nums[i...j-1] >= target
46 for (let startIndex = 0; startIndex <= arrayLength; startIndex++) {
47 // Find smallest j where prefixSum[j] - prefixSum[startIndex] >= target
48 // Equivalent to: prefixSum[j] >= prefixSum[startIndex] + target
49 const endIndex: number = binarySearch(prefixSum[startIndex] + target);
50
51 // If valid subarray found, update minimum length
52 if (endIndex <= arrayLength) {
53 minLength = Math.min(minLength, endIndex - startIndex);
54 }
55 }
56
57 // Return 0 if no valid subarray found, otherwise return minimum length
58 return minLength === arrayLength + 1 ? 0 : minLength;
59}
60
Time and Space Complexity
Time Complexity: O(n × log n)
The algorithm consists of two main operations:
- Creating the prefix sum array using
accumulate()
:O(n)
time - Iterating through each element in the prefix sum array:
O(n)
iterations- For each iteration, performing a binary search using
bisect_left()
on the prefix sum array of lengthn+1
:O(log n)
time per search
- For each iteration, performing a binary search using
- Total time:
O(n) + O(n × log n) = O(n × log n)
Space Complexity: O(n)
The algorithm uses additional space for:
- The prefix sum array
s
which storesn+1
elements (including the initial 0):O(n)
space - A few scalar variables (
ans
,i
,j
,x
):O(1)
space - Total space:
O(n) + O(1) = O(n)
Common Pitfalls
Pitfall 1: Misunderstanding the Binary Search Target
The Issue: A common mistake is searching for target
directly instead of current_sum + target
in the prefix sum array. This leads to incorrect results because we need to find where the cumulative sum reaches at least current_sum + target
, not just target
.
Incorrect Implementation:
# WRONG: This searches for target, not the required sum j = bisect_left(prefix_sums, target)
Correct Implementation:
# CORRECT: Search for current_sum + target j = bisect_left(prefix_sums, current_sum + target)
Pitfall 2: Off-by-One Errors with Array Indexing
The Issue: The prefix sum array has length n+1
while the original array has length n
. This can cause confusion when checking bounds and calculating subarray lengths.
Common Mistakes:
# WRONG: Comparing with wrong bound
if j < n: # Should be j <= n
min_length = min(min_length, j - i)
# WRONG: Using wrong initial value
min_length = n # Should be n + 1 to distinguish "not found" case
Correct Implementation:
# Initialize with n + 1 (impossible valid length)
min_length = n + 1
# Check if j is within valid bounds (can equal n)
if j <= n:
min_length = min(min_length, j - i)
Pitfall 3: Inefficient O(n²) Solution Instead of O(n log n)
The Issue: Using nested loops to check all possible subarrays instead of leveraging binary search on the sorted prefix sum array.
Inefficient Approach:
# WRONG: O(n²) time complexity
min_length = float('inf')
for i in range(n):
current_sum = 0
for j in range(i, n):
current_sum += nums[j]
if current_sum >= target:
min_length = min(min_length, j - i + 1)
break
Optimized Solution: Use the binary search approach as shown in the original solution for O(n log n) complexity.
Pitfall 4: Not Handling Edge Cases Properly
The Issue: Forgetting to handle cases where no valid subarray exists or where the entire array sum is less than target.
Incomplete Solution:
# WRONG: Returns n + 1 instead of 0 when no valid subarray exists return min_length # Should check if min_length is still n + 1
Complete Solution:
# CORRECT: Properly handle the "no solution" case return min_length if min_length <= n else 0
Which data structure is used to implement priority queue?
Recommended Readings
Binary Search Speedrun For each of the Speedrun questions you will be given a binary search related problem and a corresponding multiple choice question The multiple choice questions are related to the techniques and template s introduced in the binary search section It's recommended that you have gone through at
Prefix Sum The prefix sum is an incredibly powerful and straightforward technique Its primary goal is to allow for constant time range sum queries on an array What is Prefix Sum The prefix sum of an array at index i is the sum of all numbers from index 0 to i By
https assets algo monster cover_photos stack svg Sliding Window Maximum Monotonic Stack We have an array and a sliding window defined by a start index and an end index The sliding window moves from left of the array to right There are always k elements in the window The window
Want a Structured Path to Master System Design Too? Don’t Miss This!