Smallest subarray with sum greater than a given value | GeeksforGeeks
Given an array of positive integers and a number positive x, find the smallest subarray with sum greater than the given value.
Notice whether there is condition that all are non-negative...This problem can be solved in O(n) time using the idea used in this post
Given an array of positive integers and a number positive x, find the smallest subarray with sum greater than the given value.
arr[] = {1, 4, 45, 6, 0, 19}
x = 51
Output: 3
Minimum length subarray is {4, 45, 6}
int smallestSubWithSum(int arr[], int n, int x){ // Initialize current sum and minimum length int curr_sum = 0, min_len = n+1; // Initialize starting and ending indexes int start = 0, end = 0; while (end < n) { // Keep adding array elements while current sum // is smaller than x while (curr_sum <= x && end < n) curr_sum += arr[end++]; // If current sum becomes greater than x. while (curr_sum > x && start < n) { // Update minimum length if needed if (end - start < min_len) min_len = end - start; // if minLen==1 break; // remove starting elements curr_sum -= arr[start++]; } } return min_len;}
A little different
滑动窗口 [left, right] 初始大小为0,滑动的规则如下:
若元素之和 < s,窗口右边沿向右延伸,直到 元素之和≥s 为止。
若元素之和 ≥ s,更新最小长度。然后窗口左边沿右移一位(即移除窗口中第一个元素),重复第1步。
public int minSubArrayLen(int s, int[] nums) { if (nums.length == 0) {
return 0; } int i = 0; int j = 0; int currSum = nums[0]; int minLen = nums.length; while (i < nums.length) { if (currSum >= s) { if (minLen > j - i + 1) { minLen = j - i + 1; } currSum -= nums[i]; i++; } else { j++; if (j >= nums.length) { break; } currSum += nums[j]; } } return minLen; } }Solution 3: O(n log n) running time, and extra O(n) space.
We first compute all the prefix sums, where prefixSum[i] denotes the sum of the first i integers, i >= 0. Under this notation, the index for the prefixSum array ranges from 0 to n.
Next, for each index i, we find the minimum length of a subarray starting from i + 1 (inclusive) of which the sum >= s, using binary search. Hence, the overall running time is O(n log n).
Remarks: A slight improvement in terms of performance will be narrowing down the range of the binary search even further. Instead of searching from i to end, one can search from j to end, where j > i. One needs to change the following binarySearch() function signature to incorporate this improvement.
Pre-sum is sorted ==> all numbers are positive.
The trick is here, we do binary search(fro 0 to i) at same time we do pre-sum computation.
The trick is here, we do binary search(fro 0 to i) at same time we do pre-sum computation.
Build pre-sum array, and do binary search(0-i) at same time.
public int minSubArrayLen(int s, int[] nums) {
if(nums.length==0 || nums==null) return 0;
int min=Integer.MAX_VALUE;
int[] sum=new int[nums.length+1];
for(int i=0;i<nums.length;i++)
{
sum[i+1]=sum[i]+nums[i];
if(sum[i+1]>=s){
int j=binarySearch(0,i,sum[i+1]-s+1,sum);
if(j>-1){
min=Math.min(min,i-j+1);
}
}
}
return min==Integer.MAX_VALUE?0:min;
}
int binarySearch(int left, int right, int target, int[] sum) {
int result = -1;
while (left < right-1) {
int m = left + (right-left)/2;
if (sum[m] >= target) {
right = m-1;
} else if (sum[m] < target) {
left = m;
}
}
if (sum[right] < target) {
return right;
} else if (sum[left] < target) {
return left;
} else {
return -1;
}
}
private int buildPrefixSum(int[] nums, int[] prefixSum) { prefixSum[0] = 0; for (int i = 0; i < nums.length; i++) { prefixSum[i + 1] = prefixSum[i] + nums[i]; } return prefixSum[nums.length]; } private int binarySearch(int i, int s, int[] prefixSum) { int low = i; int high = prefixSum.length - 1; while (low <= high) { int mid = low + (high - low) / 2; if (prefixSum[mid] - prefixSum[i] < s) { // each time, it need read two values low = mid + 1; } else { if ( mid > 0 && prefixSum[mid - 1] - prefixSum[i] < s ) { return mid - i; } high = mid - 1; } } return prefixSum.length; } public int minSubArrayLen(int s, int[] nums) { if (nums.length == 0) { return 0; } int[] prefixSum = new int[nums.length + 1]; int totalSum = buildPrefixSum(nums, prefixSum); if (totalSum < s) { return 0; } int minLen = prefixSum.length - 1; for (int i = 0; i < prefixSum.length; i++) { int len = binarySearch(i, s, prefixSum); if (minLen > len) { minLen = len; } } return minLen; }
http://www.programcreek.com/2014/05/leetcode-minimum-size-subarray-sum-java/O(n*n)The outer loop picks a starting element, the inner loop considers all elements (on right side of current start) as ending element. Whenever sum of elements between current start and end becomes more than the given number, update the result if current length is smaller than the smallest length so far.
Find subarray with given sum
Given an unsorted array of nonnegative integers, find a continous subarray which adds to a given number.
O(n): two pointers window:
O(n^2)
Read full article from Smallest subarray with sum greater than a given value | GeeksforGeeks
int smallestSubWithSum(int arr[], int n, int x){ // Initilize length of smallest subarray as n+1 int min_len = n + 1; // Pick every element as starting point for (int start=0; start<n; start++) { // Initialize sum starting with current start int curr_sum = arr[start]; // If first element itself is greater if (curr_sum > x) return 1; // Try different ending points for curremt start for (int end=start+1; end<n; end++) { // add last element to current sum curr_sum += arr[end]; // If sum becomes more than x and length of // this subarray is smaller than current smallest // length, update the smallest length (or result) if (curr_sum > x && (end - start + 1) < min_len) min_len = (end - start + 1); // we can break this loop } } return min_len;}Given an unsorted array of nonnegative integers, find a continous subarray which adds to a given number.
O(n): two pointers window:
int subArraySum(int arr[], int n, int sum){ /* Initialize curr_sum as value of first element and starting point as 0 */ int curr_sum = arr[0], start = 0, i; /* Add elements one by one to curr_sum and if the curr_sum exceeds the sum, then remove starting element */ for (i = 1; i <= n; i++) { // If curr_sum exceeds the sum, then remove the starting elements while (curr_sum > sum && start < i-1) { curr_sum = curr_sum - arr[start]; start++; } // If curr_sum becomes equal to sum, then return true if (curr_sum == sum) { printf ("Sum found between indexes %d and %d", start, i-1); return 1; } // Add this element to curr_sum if (i < n) curr_sum = curr_sum + arr[i]; } // If we reach here, then no subarray printf("No subarray found"); return 0;}int subArraySum(int arr[], int n, int sum){ int curr_sum, i, j; // Pick a starting point for (i = 0; i < n; i++) { curr_sum = arr[i]; // try all subarrays starting with 'i' for (j = i+1; j <= n; j++) { if (curr_sum == sum) { printf ("Sum found between indexes %d and %d", i, j-1); return 1; } if (curr_sum > sum || j == n) break; curr_sum = curr_sum + arr[j]; } } printf("No subarray found"); return 0;}