Given an array of n positive integers and a positive integer s, find the minimal length of a subarray of which the sum ≥ s. If there isn’t one, return 0 instead.
For example, given the array [2,3,1,2,4,3] and s = 7, the subarray [4,3] has the minimal length of 2 under the problem constraint.
Analysis
We can use 2 points to mark the left and right boundaries of the sliding window. When the sum is greater than the target, shift the left pointer; when the sum is less than the target, shift the right pointer.
Java Solution – two pointers
A simple sliding window solution.
public int minSubArrayLen(int s, int[] nums) { if(nums==null || nums.length==1) return 0; int result = nums.length; int start=0; int sum=0; int i=0; boolean exists = false; while(i<=nums.length){ if(sum>=s){ exists=true; //mark if there exists such a subarray if(start==i-1){ return 1; } result = Math.min(result, i-start); sum=sum-nums[start]; start++; }else{ if(i==nums.length) break; sum = sum+nums[i]; i++; } } if(exists) return result; else return 0; } |
Similarly, we can also write it in a more readable way.
public int minSubArrayLen(int s, int[] nums) { if(nums==null||nums.length==0) return 0; int i=0; int j=0; int sum=0; int minLen = Integer.MAX_VALUE; while(j<nums.length){ if(sum<s){ sum += nums[j]; j++; }else{ minLen = Math.min(minLen, j-i); if(i==j-1) return 1; sum -=nums[i]; i++; } } while(sum>=s){ minLen = Math.min(minLen, j-i); sum -=nums[i++]; } return minLen==Integer.MAX_VALUE? 0: minLen; } |
In my mentioned solution, I don’t care whether the input array is sorted or not.
– First, I calculated the prefix sum array which will contain the sum starting from 0 to i for 0 <= i = the given sum in the problem.
– Finally, To check the direction of the binary search step, I am iterating over all possible subarrays with length equal to mid, and decide whether to go left or right according to the following explanation.
As, you can see the second step is suitable to apply binary search on it, as if we have a sub array of length l1 and its sum >= the given sum, then we don’t need to check lengths > l1, and the reverse is correct as well (If we can’t find a sub array of length l2 and its sum >= the given sum, then it means we can’t find another subarray with a length less than l2, so we will ignore all lengths < l2).
In order to format the code, user the following template:
actual code goes here
I don’t understand how can this be done using a binary search.
The input array of numbers isn’t sorted.
So the logic behind my solution is a moving window, having a length, where it ends (the traversed `i`) and the sum.
O(n) solution using two pointers approach
class Solution {
public:
int minSubArrayLen(int s, vector& nums) {
if(nums.size() == 0) return 0;
int startPosition = 0, endPosition = -1, sum = 0, minLen = INT_MAX;
for(int i = 0; i = s) {
sum -= nums[startPosition];
startPosition++;
}
if(sum >= s) minLen = min(minLen, endPosition - startPosition + 1);
}
return minLen != INT_MAX ? minLen : 0;
}
};
O(n log n) solution using Binary Search
class Solution {
public:
int minSubArrayLen(int s, vector& nums) {
if(nums.size() == 0) return 0;
/* build prefix sum array */
vector sum(nums.size());
for(int i = 0; i 0 ? sum[i - 1] : 0);
/* binary search on the minimium length */
int L = 1, R = nums.size(), ans = 0;
while(L <= R) {
int mid = (L + R) / 2;
/* check if the length mid is valid */
bool flag = false;
for(int i = 0; i + mid = s;
if(flag) break;
}
if(flag) {
ans = mid;
R = mid - 1;
}
else {
L = mid + 1;
}
}
return ans;
}
};
var arr = [2,3,1,2,4,3]
var s = 7
sum = arr[0] + arr[1]
for(var i=0, j = 1 ; i < j && j< arr.length;){
if(sum < s){
j++
sum += arr[j]
}
else {
i++
sum -= arr[i]
}
}
arr.slice(i,j)
Thanks for the reply Zaid!
Yes… It should be O(n), as both the ends of the window would slide through every number only once.
What is the time complexity of the above first code? Will it be O(n)?
Hi is my solution right?
public static int minSizeSubArray(int[] arrA, int target){
if(arrA == null || arrA.length == 0){
throw new IllegalArgumentException(“”);
}
int index = 0;
int result = Integer.MAX_VALUE;
int sum = 0;
for(int i = 0; i target){
sum = sum – arrA[index];
index++;
}
if(sum == target){
result = Math.min(result, (i – index)+1);
sum = sum – arrA[index];
index++;
}
}
return result;
}
My solution using Java’s cousin. Scala.
def minSizeSubArraySum(xs: List[Int], s: Int): Int = {
def loop(step: Int): Int =
if (xs.sliding(step).toList.exists(_.sum >= s)) step
else loop(step + 1)
if (xs.sum >= s) loop(1) else 0
}
My solution using Java’s cousin. Scala.
def minSizeSubArraySum(xs: List[Int], s: Int): Int = {
def loop(step: Int): Int =
if (xs.sliding(step).toList.exists(_.sum >= s)) step
else loop(step + 1)
if (xs.sum >= s) loop(1) else 0
}
Gives wrong result for [4,1,2,2,3,3] and s = 7. The result expected is 2 but it gives 3
I want to share my solution here. I think it’s more concise 🙂
public int minSubArrayLen(int s, int[] nums) {
if (nums == null || nums.length == 0 || s <= 0) return 0;
int min = Integer.MAX_VALUE;
int i = 0, sum = 0;
for (int j = 0; j = s) {
min = Math.min(min, j – i + 1);
sum -= nums[i++];
}
}
return min == Integer.MAX_VALUE ? 0 : min;
}
For input int a[]={2,3,1,1,8,3} and sum 7 it is giving wrong results
Dude, did you not read the problem? It says n positive integers! In what world is -1 a positive integer??
No. Sorting is not allowed here since that will alter the original arrangement of the numbers in the array. There is an implicit requirement that the initial order of the numbers in the array be preserved. Sorting will violate that requirement.
Yeah, looks like a sort is required.
For instance, array[-1, 1, 2, 1, 2, 1], sum = 4, returns 3 based on above algorithm.
But the same algo with the array being sorted returns the correct answer 2, as the sum of array [2, 2] is >= 4.
shoulldnt we have sorted the array before ?