hard Count of Range Sum
Problem Statement
Given an integer array nums and two integers lower and upper, return the number of range sums that lie between lower and upper, inclusive.
A range sum S(i, j) is calculated by summing the elements in nums from index i to index j (where i <= j).
Examples
-
Example 1:
- Input: nums =
[2, -1, 2, -3, 4], lower =0, upper =2 - Output:
7 - Explanation: The valid range sums are
S(0, 0) = 0,S(0, 1) = 1,S(2, 2) = 2,S(3, 4) = 1,S(1, 4) = 2,S(0, 2) = 1, andS(0, 3) = 0. All these sums lie within[0, 2].
- Input: nums =
-
Example 2:
- Input: nums =
[0, 3, -2, 1, -4, 2], lower =-2, upper =2 - Output:
15 - Explanation: There are a total 15 valid ranges whose sum lies within
[-2, 2].
- Input: nums =
-
Example 3:
- Input: nums =
[1, -1, 1, -1, 1],lower =0, upper =1 - Output:
12 - Explanation: The valid range sums are
S(0, 0) = 1,S(2, 2) = 1,S(4, 4) = 1,S(0, 1) = 0,S(1, 2) = 0,S(2, 3) = 0,S(3, 4) = 0,S(0, 2) = 1,S(2, 5) = 1,S(0, 3) = 0,S(1, 4) = 0,S(0, 4) = 1.
- Input: nums =
Constraints:
- 1 <= nums.length <= 105
- -231 <= nums[i] <= 231 - 1
- -105 <= lower <= upper <= 105
- The answer is guaranteed to fit in a 32-bit integer.
Try it yourself
Try solving this question here:
✅ Solution Count of Range Sum
Problem Statement
Given an integer array nums and two integers lower and upper, return the number of range sums that lie between lower and upper, inclusive.
A range sum S(i, j) is calculated by summing the elements in nums from index i to index j (where i <= j).
Examples
-
Example 1:
- Input: nums =
[2, -1, 2, -3, 4], lower =0, upper =2 - Output:
7 - Explanation: The valid range sums are
S(0, 0) = 0,S(0, 1) = 1,S(2, 2) = 2,S(3, 4) = 1,S(1, 4) = 2,S(0, 2) = 1, andS(0, 3) = 0. All these sums lie within[0, 2].
- Input: nums =
-
Example 2:
- Input: nums =
[0, 3, -2, 1, -4, 2], lower =-2, upper =2 - Output:
15 - Explanation: There are a total 15 valid ranges whose sum lies within
[-2, 2].
- Input: nums =
-
Example 3:
- Input: nums =
[1, -1, 1, -1, 1],lower =0, upper =1 - Output:
12 - Explanation: The valid range sums are
S(0, 0) = 1,S(2, 2) = 1,S(4, 4) = 1,S(0, 1) = 0,S(1, 2) = 0,S(2, 3) = 0,S(3, 4) = 0,S(0, 2) = 1,S(2, 5) = 1,S(0, 3) = 0,S(1, 4) = 0,S(0, 4) = 1.
- Input: nums =
Constraints:
- 1 <= nums.length <= 105
- -231 <= nums[i] <= 231 - 1
- -105 <= lower <= upper <= 105
- The answer is guaranteed to fit in a 32-bit integer.
Solution
To solve this problem, we use a Binary Indexed Tree (BIT) to efficiently count the number of valid range sums. The main idea is to keep track of prefix sums, which allows us to calculate the sum of any subarray in constant time by subtracting two prefix sums. As we calculate each prefix sum, we use the BIT to count how many of these prefix sums, when subtracted from the current prefix sum, fall within the [lower, upper] range.
This approach is effective because it reduces the problem of finding subarrays with sums in a certain range to a problem of counting prefix sums within a range. The BIT helps manage the range queries efficiently, which ensures that our solution scales well even with large input sizes. The overall approach is optimal in terms of both time and space complexity compared to a brute-force method.
Step-by-Step Algorithm
-
Initialize Variables:
- Define
nas the length of the input arraynums. - Initialize
ansas0to store the count of valid range sums. - Create an array
preof sizen+1to store prefix sums. The extra space is used to simplify calculations when considering sums from the start of the array.
- Define
-
Calculate Prefix Sums:
- Loop through the array
numsand calculate the prefix sum for each index. Store these prefix sums in the arraypre. - This helps us easily calculate the sum of any subarray by subtracting two prefix sums.
- Loop through the array
-
Sort the Prefix Sum Array:
- Sort the
prearray to allow us to use binary search for efficient indexing. - Sorting is important because the Binary Indexed Tree (BIT) relies on the positions of these prefix sums for correct counting.
- Sort the
-
Initialize the Binary Indexed Tree (BIT):
- Create an integer array
bitof sizepre.length + 2to act as the BIT. - The BIT will help us efficiently count how many prefix sums fall within a certain range, which is key to counting valid subarrays.
- Create an integer array
-
Iterate Over
numsArray:-
Initialize
sumto0to track the cumulative sum as we iterate throughnums. -
Update the BIT:
- Use the
bs(sum, pre)operation to find where the currentsumfits into the sortedprearray. - This position indicates the cumulative sum up to this point. We update the BIT at this index to record that this prefix sum has been encountered.
- This operation works because the BIT will later be used to count how many such sums are present that fall within the required range.
- Use the
-
Update the Cumulative Sum:
- Add the current
nums[i]tosumto update the cumulative sum.
- Add the current
-
Count Valid Range Sums:
- We want to count how many prefix sums lie within
[sum - upper, sum - lower]. - Use
bs(sum-lower, pre)to find how many prefix sums are ≤sum - lower. - Use
bs(sum-upper-1, pre)to find how many prefix sums are ≤sum - upper - 1. - The difference between these two counts gives us the number of valid subarrays ending at the current position that satisfy the condition
lower ≤ sum(i, j) ≤ upper. - The operation
ans += sum(bit, bs(sum-lower, pre)) - sum(bit, bs(sum-upper-1, pre));works because it adds the count of valid range sums up to this point.
- We want to count how many prefix sums lie within
-
-
Return the Result:
- After iterating through the entire array,
answill hold the total number of valid subarrays. - Return
ansas the final result.
- After iterating through the entire array,
Why Above Steps Work?
-
Binary Search (
bs(sum, pre)):- This function returns the position where the current cumulative sum would fit in the sorted prefix sum array. It effectively maps the cumulative sum to its index in the BIT. By updating the BIT at this position, we record that this prefix sum has occurred, enabling us to count how many times such sums fall within the desired range.
-
Counting Valid Sums:
- By using the BIT to sum up how many prefix sums are within a certain range, we can efficiently count the number of valid subarrays that satisfy the condition
lower ≤ sum(i, j) ≤ upper. The difference of sums from the BIT gives us the exact number of valid subarrays ending at the current position.
- By using the BIT to sum up how many prefix sums are within a certain range, we can efficiently count the number of valid subarrays that satisfy the condition
Algorithm Walkthrough
Input: nums = [2, -1, 2, -3, 4], lower = 0, upper = 2
-
Initialization:
n = 5(length ofnums)ans = 0(to store the count of valid range sums)pre = [0, 0, 0, 0, 0, 0](prefix sum array initialized with an extra space)
-
Calculate Prefix Sums:
- The final prefix sum is
pre = [0, 2, 1, 3, 0, 4]
- The final prefix sum is
-
Sort the Prefix Sum Array:
- Sort
preresulting inpre = [0, 0, 1, 2, 3, 4]
- Sort
-
Initialize the Binary Indexed Tree (BIT):
bit = [0, 0, 0, 0, 0, 0, 0, 0](BIT array initialized with extra space)
-
Iterate Over
numsArray:-
Iteration 1 (
i = 0):sum = 0(initial cumulative sum)- Update the BIT:
bs(sum, pre)finds the position ofsum = 0inpre, which is index2- Update BIT at index
2, sobit = [0, 0, 0, 1, 1, 0, 0, 0]
- Update Cumulative Sum:
sum = sum + nums[0] = 0 + 2 = 2
- Count Valid Range Sums:
bs(sum-lower, pre) = bs(2-0, pre) = 4(position ofsum-lowerinpre)bs(sum-upper-1, pre) = bs(2-2-1, pre) = 0(position ofsum-upper-1inpre)- Count =
sum(bit, 4) - sum(bit, 0) = 1 - 0 = 1 - Add
1toans, soans = 1
-
Iteration 2 (
i = 1):sum = 2(from the previous iteration)- Update the BIT:
bs(sum, pre)finds the position ofsum = 2inpre, which is index4- Update BIT at index
4, sobit = [0, 0, 0, 1, 1, 1, 1, 0]
- Update Cumulative Sum:
sum = sum + nums[1] = 2 + (-1) = 1
- Count Valid Range Sums:
bs(sum-lower, pre) = bs(1-0, pre) = 3(position ofsum-lowerinpre)bs(sum-upper-1, pre) = bs(1-2-1, pre) = 0(position ofsum-upper-1inpre)- Count =
sum(bit, 3) - sum(bit, 0) = 1 - 0 = 1 - Add
1toans, soans = 2
-
Iteration 3 (
i = 2):sum = 1(from the previous iteration)- Update the BIT:
bs(sum, pre)finds the position ofsum = 1inpre, which is index3- Update BIT at index
3, sobit = [0, 0, 0, 1, 2, 1, 1, 0]
- Update Cumulative Sum:
sum = sum + nums[2] = 1 + 2 = 3
- Count Valid Range Sums:
bs(sum-lower, pre) = bs(3-0, pre) = 5(position ofsum-lowerinpre)bs(sum-upper-1, pre) = bs(3-2-1, pre) = 2(position ofsum-upper-1inpre)- Count =
sum(bit, 5) - sum(bit, 2) = 3 - 1 = 2 - Add
2toans, soans = 4
-
Iteration 4 (
i = 3):sum = 3(from the previous iteration)- Update the BIT:
bs(sum, pre)finds the position ofsum = 3inpre, which is index5- Update BIT at index
5, sobit = [0, 0, 0, 1, 2, 1, 2, 0]
- Update Cumulative Sum:
sum = sum + nums[3] = 3 + (-3) = 0
- Count Valid Range Sums:
bs(sum-lower, pre) = bs(0-0, pre) = 2(position ofsum-lowerinpre)bs(sum-upper-1, pre) = bs(0-2-1, pre) = 0(position ofsum-upper-1inpre)- Count =
sum(bit, 2) - sum(bit, 0) = 1 - 0 = 1 - Add
1toans, soans = 5
-
Iteration 5 (
i = 4):sum = 0(from the previous iteration)- Update the BIT:
bs(sum, pre)finds the position ofsum = 0inpre, which is index2- Update BIT at index
2, sobit = [0, 0, 0, 2, 3, 1, 2, 0]
- Update Cumulative Sum:
sum = sum + nums[4] = 0 + 4 = 4
- Count Valid Range Sums:
bs(sum-lower, pre) = bs(4-0, pre) = 6(position ofsum-lowerinpre)bs(sum-upper-1, pre) = bs(4-2-1, pre) = 3(position ofsum-upper-1inpre)- Count =
sum(bit, 6) - sum(bit, 3) = 5 - 3 = 2 - Add
2toans, soans = 7
-
-
Final Result:
- After all iterations,
ansholds the total count of valid range sums, which is7. - Return
ans = 7as the final output.
- After all iterations,
Code
import java.util.Arrays;
class Solution {
public int countRangeSum(int[] nums, int lower, int upper) {
int n = nums.length,
ans = 0; // Initialize length of nums array and result variable
long[] pre = new long[n + 1];
// Calculate the prefix sums for the array
for (int i = 0; i < n; i++) {
pre[i + 1] = nums[i] + pre[i];
}
Arrays.sort(pre); // Sort the prefix sum array for binary search
int[] bit = new int[pre.length + 2];
long sum = 0;
// Iterate through each element in nums to calculate valid range sums
for (int i = 0; i < n; i++) {
update(bit, bs(sum, pre), 1); // Update the BIT with the current cumulative sum
sum += nums[i];
// Count the number of valid range sums that lie between lower and upper
ans +=
sum(bit, bs(sum - lower, pre)) - sum(bit, bs(sum - upper - 1, pre));
}
return ans;
}
// Binary search function to find the index of the first number greater than the given sum
private int bs(long sum, long[] pre) {
int lo = 0,
hi = pre.length; // Set initial low and high pointers for binary search
while (lo < hi) {
int mid = (lo + hi) >> 1; // Calculate mid index
if (pre[mid] > sum) {
hi = mid; // Move high pointer to mid
} else {
lo = mid + 1; // Move low pointer to mid + 1
}
}
return lo;
}
// Function to update the BIT
private void update(int[] bit, int idx, int inc) {
for (++idx; idx < bit.length; idx += idx & -idx) {
// Update all relevant indices in the BIT
bit[idx] += inc; // Increment the BIT value at the current index
}
}
private int sum(int[] bit, int idx) {
int ans = 0;
for (++idx; idx > 0; idx -= idx & -idx) {
// Iterate through the BIT to sum up values
ans += bit[idx]; // Add the BIT value at the current index to the result
}
return ans;
}
public static void main(String[] args) {
Solution solution = new Solution();
// Example 1
int[] nums1 = { 2, -1, 2, -3, 4 };
int lower1 = 0,
upper1 = 2;
System.out.println(
"Example 1 Output: " + solution.countRangeSum(nums1, lower1, upper1)
);
// Example 2
int[] nums2 = { 0, 3, -2, 1, -4, 2 };
int lower2 = -2,
upper2 = 2;
System.out.println(
"Example 2 Output: " + solution.countRangeSum(nums2, lower2, upper2)
);
// Example 3
int[] nums3 = { 1, -1, 1, -1, 1 };
int lower3 = 0,
upper3 = 1;
System.out.println(
"Example 3 Output: " + solution.countRangeSum(nums3, lower3, upper3)
);
}
}
Complexity Analysis
Time Complexity
- Prefix Sum Calculation: The prefix sum is calculated in
time, where nis the length of the input arraynums. - Sorting: Sorting the prefix sum array takes
time. - Binary Indexed Tree Operations:
- The
updateandsumBITfunctions operate intime. - There are
nelements, and for each element, we perform constant-time operations with the BIT, resulting intime.
- The
Overall, the time complexity is
Space Complexity
- Prefix Sum Array: The prefix sum array requires
space. - Binary Indexed Tree: The BIT also requires
space. - Auxiliary Space: Additional space is used for storing the variables, but they are of constant space, so the space complexity remains
.
Thus, the overall space complexity is
🤖 Don't fully get this? Learn it with Claude
Stuck on Count of Range Sum? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.
Progressively stronger hints — you still solve it.
I'm working on the problem **Count of Range Sum** (DSA). Give me a HINT LADDER: start with the tiniest nudge, then wait. Only reveal the next, stronger hint when I ask. Do NOT show the full solution unless I type 'show solution'. Keep me doing the thinking. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
See the technique, not just code.
Explain the optimal approach to **Count of Range Sum** with a VISUAL walkthrough: trace it on a small concrete example using ASCII art / a step-by-step diagram, narrate what changes each step, then give time & space complexity with a one-line derivation. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Catch bugs, edge cases, sub-optimality.
I'll paste my solution to **Count of Range Sum**. Review it for correctness, missed edge cases, and time/space complexity, then coach me toward the optimal — don't just rewrite it. Ask me to paste my code now. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Lock in recognition with look-alikes.
Give me 2 problems that use the SAME underlying pattern as **Count of Range Sum**. For each, let me attempt first, then review my answer and name the trigger signal that reveals the pattern. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.