🧠
Prefix Sum + Binary Search
💡 This approach improves over brute force by using prefix sums and binary search to find the minimal subarray efficiently.
Intuition
Compute prefix sums to quickly get subarray sums, then for each start index, binary search the smallest end index where sum >= target.
Algorithm
- Compute prefix sums array where prefix[i] is sum of nums[0..i-1].
- For each start index, calculate needed sum = target + prefix[start].
- Use binary search on prefix sums to find minimal end index with prefix[end] >= needed sum.
- Update minimal length if such end index found.
💡 Prefix sums let us get subarray sums in O(1), binary search finds the minimal end index efficiently.
import bisect
def min_subarray_len(target, nums):
n = len(nums)
prefix = [0] * (n + 1)
for i in range(n):
prefix[i+1] = prefix[i] + nums[i]
min_length = float('inf')
for start in range(n):
needed = target + prefix[start]
end = bisect.bisect_left(prefix, needed)
if end <= n:
min_length = min(min_length, end - start)
return 0 if min_length == float('inf') else min_length
# Driver code
if __name__ == '__main__':
print(min_subarray_len(7, [2,3,1,2,4,3])) # Output: 2
Line Notes
import bisectImport binary search module for efficient searching
prefix = [0] * (n + 1)Initialize prefix sums array with extra space for 0 prefix
prefix[i+1] = prefix[i] + nums[i]Build prefix sums cumulatively
needed = target + prefix[start]Calculate required prefix sum to reach target from start
end = bisect.bisect_left(prefix, needed)Binary search for minimal end index with sufficient sum
if end <= nCheck if valid end index found within array bounds
min_length = min(min_length, end - start)Update minimal length if better subarray found
import java.util.*;
public class Solution {
public static int minSubArrayLen(int target, int[] nums) {
int n = nums.length;
int[] prefix = new int[n + 1];
for (int i = 0; i < n; i++) {
prefix[i + 1] = prefix[i] + nums[i];
}
int minLength = Integer.MAX_VALUE;
for (int start = 0; start < n; start++) {
int needed = target + prefix[start];
int end = Arrays.binarySearch(prefix, needed);
if (end < 0) {
end = -end - 1;
}
if (end <= n) {
minLength = Math.min(minLength, end - start);
}
}
return minLength == Integer.MAX_VALUE ? 0 : minLength;
}
public static void main(String[] args) {
System.out.println(minSubArrayLen(7, new int[]{2,3,1,2,4,3})); // Output: 2
}
}
Line Notes
int[] prefix = new int[n + 1];Create prefix sums array with extra space
prefix[i + 1] = prefix[i] + nums[i];Build prefix sums cumulatively
int needed = target + prefix[start];Calculate required prefix sum for subarray
int end = Arrays.binarySearch(prefix, needed);Binary search for minimal end index
if (end < 0) { end = -end - 1; }Adjust insertion point if exact match not found
if (end <= n)Check if end index is valid
minLength = Math.min(minLength, end - start);Update minimal length if better subarray found
#include <iostream>
#include <vector>
#include <algorithm>
#include <climits>
using namespace std;
int minSubArrayLen(int target, vector<int>& nums) {
int n = nums.size();
vector<int> prefix(n + 1, 0);
for (int i = 0; i < n; i++) {
prefix[i + 1] = prefix[i] + nums[i];
}
int minLength = INT_MAX;
for (int start = 0; start < n; start++) {
int needed = target + prefix[start];
auto it = lower_bound(prefix.begin(), prefix.end(), needed);
if (it != prefix.end()) {
int end = it - prefix.begin();
minLength = min(minLength, end - start);
}
}
return minLength == INT_MAX ? 0 : minLength;
}
int main() {
vector<int> nums = {2,3,1,2,4,3};
cout << minSubArrayLen(7, nums) << endl; // Output: 2
return 0;
}
Line Notes
vector<int> prefix(n + 1, 0);Initialize prefix sums vector with zeroes
prefix[i + 1] = prefix[i] + nums[i];Build prefix sums cumulatively
int needed = target + prefix[start];Calculate required prefix sum for subarray
auto it = lower_bound(prefix.begin(), prefix.end(), needed);Binary search for minimal end index
if (it != prefix.end())Check if valid end index found
int end = it - prefix.begin();Calculate index from iterator
minLength = min(minLength, end - start);Update minimal length if better subarray found
function minSubArrayLen(target, nums) {
const n = nums.length;
const prefix = new Array(n + 1).fill(0);
for (let i = 0; i < n; i++) {
prefix[i + 1] = prefix[i] + nums[i];
}
let minLength = Infinity;
function binarySearch(arr, x) {
let left = 0, right = arr.length - 1;
while (left <= right) {
let mid = Math.floor((left + right) / 2);
if (arr[mid] >= x) right = mid - 1;
else left = mid + 1;
}
return left;
}
for (let start = 0; start < n; start++) {
let needed = target + prefix[start];
let end = binarySearch(prefix, needed);
if (end <= n) {
minLength = Math.min(minLength, end - start);
}
}
return minLength === Infinity ? 0 : minLength;
}
// Test
console.log(minSubArrayLen(7, [2,3,1,2,4,3])); // Output: 2
Line Notes
const prefix = new Array(n + 1).fill(0);Initialize prefix sums array with zeroes
prefix[i + 1] = prefix[i] + nums[i];Build prefix sums cumulatively
function binarySearch(arr, x)Custom binary search to find minimal index with value >= x
let needed = target + prefix[start];Calculate required prefix sum for subarray
let end = binarySearch(prefix, needed);Find minimal end index using binary search
if (end <= n)Check if end index is valid
minLength = Math.min(minLength, end - start);Update minimal length if better subarray found
Prefix sums take O(n), and for each start index we do a binary search O(log n), total O(n log n). Extra space for prefix sums.
💡 For n=1000, this means about 10,000 operations, much faster than brute force.
Interview Verdict: Accepted, but sliding window is more optimal
This approach is a good intermediate step but sliding window is preferred for linear time.