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].

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:

  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 first j where s[j] >= s[i] + 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 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
37
1class 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}
50
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            // 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};
44
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 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}
46

Solution 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 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, 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 = -1
      • mid = 5: s[5] = 12 < 15left = 6
      • mid = 6: s[6] = 15 >= 15first_true_index = 6, right = 5
      • left > right, exit loop
    • first_true_index = 6, subarray length = 6 - 4 = 2
    • Update: ans = min(3, 2) = 2
  • 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 = -1
      • mid = 5: s[5] = 12 < 19left = 6
      • mid = 6: s[6] = 15 < 19left = 7
      • left > right, exit loop
    • first_true_index = -1, no valid subarray starting at position 5

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 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: 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
Loading...
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

How does quick sort divide the problem into subproblems?


Recommended Readings

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

Load More