327. Count of Range Sum
Given an integer array nums and two integers lower and upper, return the number of range sums that lie in [lower, upper] inclusive.
Range sum S(i, j) is defined as the sum of the elements in nums between indices i and j inclusive, where i <= j.
Example 1:
Input: nums = [-2,5,-1], lower = -2, upper = 2
Output: 3
Explanation: The three ranges are: [0,0], [2,2], and [0,2] and their respective sums are: -2, -1, 2.
Example 2:
Input: nums = [0], lower = 0, upper = 0
Output: 1
Constraints:
- 1 < = n u m s . l e n g t h < = 1 0 5 1 <= nums.length <= 10^5 1<=nums.length<=105
- − 2 31 < = n u m s [ i ] < = 2 31 − 1 -2^{31} <= nums[i] <= 2^{31} - 1 −231<=nums[i]<=231−1
- − 1 0 5 < = l o w e r < = u p p e r < = 1 0 5 -10^5 <= lower <= upper <= 10^5 −105<=lower<=upper<=105
- The answer is guaranteed to fit in a 32-bit integer.
From: LeetCode
Link: 327. Count of Range Sum
Solution:
Ideas:
-
Prefix Sum Array: We create a prefix sum array where prefixSums[i] represents the sum of the array elements from the start to the i-th index. This allows us to calculate the sum of any subarray [i, j] as prefixSums[j+1] - prefixSums[i].
-
Merge Sort: The core idea of the solution is to use a modified merge sort. During the merge step, we count the number of valid ranges [i, j] that satisfy the condition lower <= S(i, j) <= upper. This is done by maintaining the order of the prefix sums while counting how many sums in the right half of the array fall within the desired range relative to each sum in the left half.
-
Counting with Binary Search: Within the merge step, we use two pointers to determine the range [lower, upper] for each prefix sum in the left half compared to prefix sums in the right half. This ensures that the solution remains efficient even for large arrays.
Code:
c
long* temp;
int mergeCount(long* prefixSums, int left, int right, int lower, int upper) {
if (left >= right) {
return 0;
}
int mid = left + (right - left) / 2;
int count = mergeCount(prefixSums, left, mid, lower, upper) + mergeCount(prefixSums, mid + 1, right, lower, upper);
int j = mid + 1, k = mid + 1, t = mid + 1;
int r = 0;
for (int i = left; i <= mid; ++i) {
while (j <= right && prefixSums[j] - prefixSums[i] < lower) j++;
while (k <= right && prefixSums[k] - prefixSums[i] <= upper) k++;
while (t <= right && prefixSums[t] < prefixSums[i]) temp[r++] = prefixSums[t++];
temp[r++] = prefixSums[i];
count += k - j;
}
for (int i = 0; i < t - left; ++i) {
prefixSums[left + i] = temp[i];
}
return count;
}
int countRangeSum(int* nums, int numsSize, int lower, int upper) {
if (numsSize == 0) {
return 0;
}
long* prefixSums = (long*)malloc((numsSize + 1) * sizeof(long));
temp = (long*)malloc((numsSize + 1) * sizeof(long));
prefixSums[0] = 0;
for (int i = 0; i < numsSize; ++i) {
prefixSums[i + 1] = prefixSums[i] + nums[i];
}
int result = mergeCount(prefixSums, 0, numsSize, lower, upper);
free(prefixSums);
free(temp);
return result;
}