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].
The feasible function: For each position j in the prefix sum array, we ask: "Is s[j] >= s[i] + target?" This creates a boolean pattern of [false, false, ..., true, true, ...]. We want to find the first position where this becomes true using binary search.
The algorithm becomes:
- Build the prefix sum array
swheres[0] = 0ands[i]= sum of firstielements - For each possible starting position
i, use binary search to find the firstjwheres[j] >= s[i] + target - 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 Implementation
1from typing import List
2from itertools import accumulate
3
4
5class Solution:
6 def minSubArrayLen(self, target: int, nums: List[int]) -> int:
7 # Get the length of the input array
8 n = len(nums)
9
10 # Create prefix sum array with initial value 0
11 # prefix_sums[i] represents sum of nums[0:i]
12 prefix_sums = list(accumulate(nums, initial=0))
13
14 # Initialize minimum length to n+1 (impossible value)
15 min_length = n + 1
16
17 # Iterate through each position in prefix sum array
18 for i in range(n + 1):
19 # Binary search template to find first j where prefix_sums[j] >= prefix_sums[i] + target
20 left, right = i, n
21 first_true_index = -1
22
23 while left <= right:
24 mid = (left + right) // 2
25 if prefix_sums[mid] >= prefix_sums[i] + target:
26 first_true_index = mid
27 right = mid - 1
28 else:
29 left = mid + 1
30
31 # If valid position found, update minimum length
32 if first_true_index != -1:
33 min_length = min(min_length, first_true_index - i)
34
35 # Return minimum length if found, otherwise return 0
36 return min_length if min_length <= n else 0
371class Solution {
2 /**
3 * Find the minimal length of a contiguous subarray whose sum is >= target.
4 * Uses prefix sum array and binary search template.
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 // Binary search template to find first j where prefixSum[j] >= prefixSum[i] + target
26 int left = i;
27 int right = n;
28 int firstTrueIndex = -1;
29
30 while (left <= right) {
31 int mid = left + (right - left) / 2;
32 if (prefixSum[mid] >= prefixSum[i] + target) {
33 firstTrueIndex = mid;
34 right = mid - 1;
35 } else {
36 left = mid + 1;
37 }
38 }
39
40 // If valid position found, update minimum length
41 if (firstTrueIndex != -1) {
42 minLength = Math.min(minLength, firstTrueIndex - i);
43 }
44 }
45
46 // Return the result, or 0 if no valid subarray found
47 return minLength <= n ? minLength : 0;
48 }
49}
501class 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 // Binary search template to find first j where prefixSum[j] >= prefixSum[i] + target
20 int left = i;
21 int right = n;
22 int firstTrueIndex = -1;
23
24 while (left <= right) {
25 int mid = left + (right - left) / 2;
26 if (prefixSum[mid] >= prefixSum[i] + target) {
27 firstTrueIndex = mid;
28 right = mid - 1;
29 } else {
30 left = mid + 1;
31 }
32 }
33
34 // If valid position found, update minimum length
35 if (firstTrueIndex != -1) {
36 minLength = min(minLength, firstTrueIndex - i);
37 }
38 }
39
40 // Return the minimum length if found, otherwise return 0
41 return minLength <= n ? minLength : 0;
42 }
43};
441/**
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 n: number = nums.length;
9
10 // Build prefix sum array where prefixSum[i] = sum of nums[0...i-1]
11 const prefixSum: number[] = new Array(n + 1).fill(0);
12 for (let i = 0; i < n; i++) {
13 prefixSum[i + 1] = prefixSum[i] + nums[i];
14 }
15
16 // Initialize answer with impossible value (n + 1)
17 let minLength: number = n + 1;
18
19 // For each starting position i, find the smallest ending position j
20 // such that sum of nums[i...j-1] >= target
21 for (let i = 0; i <= n; i++) {
22 // Binary search template to find first j where prefixSum[j] >= prefixSum[i] + target
23 let left: number = i;
24 let right: number = n;
25 let firstTrueIndex: number = -1;
26
27 while (left <= right) {
28 const mid: number = Math.floor((left + right) / 2);
29 if (prefixSum[mid] >= prefixSum[i] + target) {
30 firstTrueIndex = mid;
31 right = mid - 1;
32 } else {
33 left = mid + 1;
34 }
35 }
36
37 // If valid subarray found, update minimum length
38 if (firstTrueIndex !== -1) {
39 minLength = Math.min(minLength, firstTrueIndex - i);
40 }
41 }
42
43 // Return 0 if no valid subarray found, otherwise return minimum length
44 return minLength === n + 1 ? 0 : minLength;
45}
46Solution Approach
Let's walk through the implementation step by step, using the binary search template.
Step 1: Build the Prefix Sum Array
We create a prefix sum array s where s[i] represents the sum of the first i elements:
s = list(accumulate(nums, initial=0))
The initial=0 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.
Step 3: Binary Search Template
For each starting position i, we use the binary search template to find the first j where s[j] >= s[i] + target:
left, right = i, n first_true_index = -1 while left <= right: mid = (left + right) // 2 if prefix_sums[mid] >= prefix_sums[i] + target: # feasible condition first_true_index = mid right = mid - 1 else: left = mid + 1
Step 4: Update Minimum Length
If first_true_index != -1 (meaning we found a valid ending position), we update our answer:
if first_true_index != -1:
ans = min(ans, first_true_index - i)
The length of the subarray is first_true_index - i.
Step 5: Return the Result
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 O(log n) 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, 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 with Template
Now we iterate through each position and use the binary search template:
-
i = 4,
s[4] = 8:- Need to find first j where
s[j] >= 8 + 7 = 15 - Binary search with template:
left = 4, right = 6, first_true_index = -1mid = 5:s[5] = 12 < 15→left = 6mid = 6:s[6] = 15 >= 15→first_true_index = 6,right = 5left > right, exit loop
first_true_index = 6, subarray length = 6 - 4 = 2- Update:
ans = min(3, 2) = 2
- Need to find first j where
-
i = 5,
s[5] = 12:- Need to find first j where
s[j] >= 12 + 7 = 19 - Binary search with template:
left = 5, right = 6, first_true_index = -1mid = 5:s[5] = 12 < 19→left = 6mid = 6:s[6] = 15 < 19→left = 7left > right, exit loop
first_true_index = -1, no valid subarray starting at position 5
- Need to find first 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.
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
swhich storesn+1elements (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: Using the Wrong Binary Search Template Variant
The Issue: Using while left < right with right = mid instead of the correct template with first_true_index.
Incorrect Implementation:
# WRONG: Using incorrect template while left < right: mid = (left + right) // 2 if prefix_sums[mid] >= target_sum: right = mid else: left = mid + 1 return left # May return out-of-bounds index
Correct Implementation:
first_true_index = -1 while left <= right: mid = (left + right) // 2 if prefix_sums[mid] >= target_sum: first_true_index = mid right = mid - 1 else: left = mid + 1 # Check first_true_index != -1 before using
Pitfall 2: Misunderstanding the Binary Search Target
The Issue: Searching for target directly instead of prefix_sums[i] + target.
Incorrect Implementation:
# WRONG: This searches for target, not the required sum if prefix_sums[mid] >= target: # Should be prefix_sums[i] + target
Correct Implementation:
# CORRECT: Search for prefix_sums[i] + target if prefix_sums[mid] >= prefix_sums[i] + target:
Pitfall 3: 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.
Common Mistakes:
# WRONG: Using wrong initial value min_length = n # Should be n + 1 to distinguish "not found" case # WRONG: Checking first_true_index incorrectly if first_true_index <= n: # Should check first_true_index != -1
Correct Implementation:
min_length = n + 1
if first_true_index != -1:
min_length = min(min_length, first_true_index - i)
Pitfall 4: Not Handling Edge Cases Properly
The Issue: Forgetting to handle cases where no valid subarray exists.
Incomplete Solution:
# WRONG: Returns n + 1 instead of 0 when no valid subarray exists return min_length
Complete Solution:
# CORRECT: Properly handle the "no solution" case return min_length if min_length <= n else 0
How does quick sort divide the problem into subproblems?
Recommended Readings
https assets algo monster cover_photos Binary_Search svg Binary Search Intuition Binary search is an efficient array search algorithm It works by narrowing down the search range by half each time If you have looked up a word in a physical dictionary you've already used binary search in real life Let's
Prefix Sum Given an array of integers arr and a target value find a subarray that sums to the target Return the start and end indices of the subarray Input arr 1 20 3 30 5 4 target 7 Output 1 4 Explanation The subarray 20 3 30 from index 1 inclusive
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!