Facebook Pixel

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, return 0

For example:

  • If nums = [2, 3, 1, 2, 4, 3] and target = 7, the subarray [4, 3] has sum = 7, which is the shortest subarray meeting the requirement, so the answer is 2
  • If nums = [1, 1, 1, 1] and target = 10, no subarray can sum to at least 10, so the answer is 0

The key constraint is that all integers in nums are positive, which allows for certain optimization techniques in solving this problem efficiently.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

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:

  1. Build the prefix sum array s where s[0] = 0 and s[i] = sum of first i elements
  2. For each possible starting position i, use binary search to find the earliest ending position j where the subarray sum is at least target
  3. 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 Evaluator

Example 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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

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 length n+1: O(log n) time per search
  • 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 stores n+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
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Which data structure is used to implement priority queue?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More