package com.freetymekiyan.algorithms.level.medium;
/**
* 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.
* <p>
* For example, given the array [2,3,1,2,4,3] and s = 7,
* the subarray [4,3] has the minimal length under the problem constraint.
* <p>
* click to show more practice.
* <p>
* More practice:
* If you have figured out the O(n) solution, try coding another solution of which the time complexity is O(n log n).
* <p>
* Company Tags: Facebook
* Tags: Array, Two Pointers, Binary Search
* Similar Problems: (H) Minimum Window Substring, (M) Maximum Size Subarray Sum Equals k
*/
public class MinSizeSubarraySum {
/**
* Two Pointers. O(n) Time.
* Use start and end index to represent a window.
* Store the window sum and min length.
* Move the end index and update window sum.
* If window sum >= s, means we are able to remove some value from ahead and get smaller window.
* Move the start index and update sum.
* Update min length.
*/
public int minSubArrayLen(int s, int[] nums) {
if (nums == null || nums.length == 0) {
return 0;
}
int sum = 0;
int min = Integer.MAX_VALUE;
for (int start = 0, end = 0; end < nums.length; end++) {
sum += nums[end];
while (sum >= s) {
min = Math.min(min, end - start + 1);
sum -= nums[start++];
}
}
return min == Integer.MAX_VALUE ? 0 : min; // Min length can be MAX, then no window is found.
}
/**
* Binary Search. O(nlogn) Time.
* Binary search for a window size.
* Use a helper function to check whether this window exists.
* If it exists, then we can have smaller window. Record minimum size.
* If it doesn't, then we should make the window larger.
*/
public int minSubArrayLen2(int s, int[] nums) {
int lo = 1;
int hi = nums.length;
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (isWindowExist(mid, nums, s)) {
hi = mid;
} else {
lo = mid + 1;
}
}
return isWindowExist(lo, nums, s) ? lo : 0;
}
/**
* Array, O(n) Time.
* Iterate the array and check whether the sum is larger than s.
* If larger, return true. Otherwise false.
*/
private boolean isWindowExist(int size, int[] nums, int s) {
int sum = 0;
for (int i = 0; i < nums.length; i++) {
if (i >= size) {
sum -= nums[i - size];
}
sum += nums[i];
if (sum >= s) {
return true;
}
}
return false;
}
}