Number of subarrays having sum in a given range
Last Updated :
19 Apr, 2024
Given an array arr[] of integers and a range (L, R). Find the number of subarrays having sum in the range L to R.
Examples:
Input: arr = { -2, 4, 1, -2}, lower = -4, upper = 1
Output: 5
Explanation: The pairs that are present here are –
- (1, 1) = [-2] , sum = -2
- (1, 4) = [-2, 4, 1, -2] , sum = 1
- (3, 3) = [1] , sum = 1
- (3, 4) = [1, -2] , sum = -1
- (4, 4) = [-2] , sum = -2
Input : arr[] = {2, 3, 5, 8}, L = 4, R = 13
Output : 6
Explanation: The subarrays are {2, 3}, {2, 3, 5}, {3, 5}, {5}, {5, 8}, {8}.
Number of subarrays having sum in a given range using Nested loops:
The basic approach to solve this type of question is to try all possible case using brute force method and count all the pair whose sum lie in the range [lower, uppper].
Below is the implementation of the above approach:
C++
#include <iostream>
#include <vector>
using namespace std;
int getCount(vector<int> arr, int n, int lower, int upper) {
int count = 0;
for(int i=0; i<n; i++) {
int sum = 0;
for(int j=i; j<n; j++) {
sum += arr[j];
if(sum >= lower and sum <= upper) {
count++;
}
}
}
return count;
}
int main() {
int n = 4;
vector<int> arr = {-2, 4, 1, -2};
int lower = -4, upper = 1;
int answer = getCount(arr, n, lower, upper);
cout << answer << endl;
return 0;
}
Time Complexity: O(n^2)
Auxiliary Space: O(1)
Number of subarrays having sum in a given range using Merge Sort:
We will use Merge sort and prefix-sum to solve this problem. we will find the range from the small sorted arrays in the prefix array that lies in the range [lower, upper]. We use prefix array to track the sum and check if the pair lies in the range lower bound and upper bound then lower <= prefix[j] – prefix[i-1] <= upper or lower + prefix[i-1] <= prefix[j] <= upper + prefix[i-1]
Step-by-step approach:
- Calculate mid of the array by using (start + end)/2
- Then Recursivly call the function in two seperate half (start, mid) and (mid+1, end).
- After this Calls the two seperated array (start, mid) and (mid+1, end) are sorted in itself so we can calculate the range of the sum that lies in the prefix array.
- We will iterate first half (let’s say i) and find the range in the second half(let’s say j) such that prefix[j] should lie in the given range [prefix[i-1 + lower, prefix[i-1]+ upper].
- Count the number of pairs from the range.
- When the iteration of i is finished. then we will merge the two half into a single array.
Below is the implementation of the above approach:
C++
#include <iostream>
#include <vector>
using namespace std;
// By Nitin Patel
// Function to merge two sorted subarrays of a given array
void merge(long long start, long long end,
vector<long long>& prefix)
{
long long n = end - start + 1;
long long mid = (start + end) / 2;
vector<long long> temp(n, 0);
long long i = start;
long long j = mid + 1;
long long k = 0;
// Merge the two subarrays in sorted order
while (i <= mid and j <= end) {
if (prefix[i] <= prefix[j]) {
temp[k++] = prefix[i++];
}
else {
temp[k++] = prefix[j++];
}
}
// Copy the remaining elements of the left subarray, if
// any
while (i <= mid) {
temp[k++] = prefix[i++];
}
// Copy the remaining elements of the right subarray, if
// any
while (j <= end) {
temp[k++] = prefix[j++];
}
// Copy the merged subarray back to the original array
for (int t = start; t <= end; t++) {
prefix[t] = temp[t - start];
}
}
// Recursive function to perform merge sort and count
// inversions
long long mergeSort(long long start, long long end,
vector<long long>& prefix, int lower,
int upper)
{
if (start == end) {
long long val = prefix[start];
// Check if the current element lies within the
// specified range
if (val >= (long long)lower
and val <= (long long)upper) {
return 1; // Count the element if it's within
// the range
}
else {
return 0; // Otherwise, don't count it
}
}
long long mid
= (start
+ ((end - start)
>> 1)); // Calculate the middle index
long long ans = 0; // Initialize the inversion count
// Recursively count inversions in the left and right
// halves
ans += mergeSort(start, mid, prefix, lower, upper);
ans += mergeSort(mid + 1, end, prefix, lower, upper);
// Count inversions involving elements from the left and
// right halves
long long i = start;
long long j = mid + 1;
long long k = mid + 1;
while (i <= mid) {
long long lowerbound = lower + prefix[i],
upperbound = upper + prefix[i];
// Find the index in the right half where elements
// are greater than the upper bound
while (j <= end and (prefix[j]) <= upperbound) {
j++;
}
// Find the index in the right half where elements
// are less than the lower bound
while (k <= end and (prefix[k]) < lowerbound) {
k++;
}
// Count the number of inversions involving elements
// from the left half and the right half
ans += (j - k);
i++;
}
// Merge the sorted halves
merge(start, end, prefix);
return ans;
}
// Function to count the number of elements within a given
// range in a sorted array
int getCount(vector<int>& nums, int n, int lower, int upper)
{
vector<long long> prefix(
n + 1, 0); // Create a prefix sum array
for (long long i = 1; i <= n; i++) {
prefix[i] = prefix[i - 1]
+ nums[i - 1]; // Calculate the prefix
// sum at each index
}
return mergeSort(
1, n, prefix, lower,
upper); // Perform merge sort and count inversions
}
int main()
{
int n = 4;
vector<int> arr = { -2, 4, 1, -2 };
int lower = -4, upper = 1;
int answer = getCount(arr, n, lower, upper);
cout << answer << endl;
return 0;
}
Time Complexity: O(n log n)
Auxiliary Space: O(n)
Like Article
Suggest improvement
Share your thoughts in the comments
Please Login to comment...