AlgoMaster Logo

Count of Range Sum

hardFrequencyUpdated September 21, 2026

Understanding the Problem

We need to count how many contiguous subarrays have a sum that falls within the range [lower, upper]. A range sum S(i, j) is the sum of elements from index i to index j.

A brute force checks every pair (i, j) and computes the subarray sum, which is too slow at this input size.

Prefix sums reframe the problem. If we define prefix[0] = 0 and prefix[k] = nums[0] + nums[1] + ... + nums[k-1], then the range sum S(i, j) = prefix[j+1] - prefix[i]. So the problem becomes: for how many pairs (i, j) with i < j does lower <= prefix[j] - prefix[i] <= upper hold? This is an inversion-counting variant on the prefix sum array.

Key Constraints:

  • 1 <= nums.length <= 10^5 --> With n up to 100,000, an O(n^2) solution means roughly 10^10 operations. That won't pass. We need O(n log n) or better.
  • -2^31 <= nums[i] <= 2^31 - 1 --> The full 32-bit integer range. Prefix sums can overflow int, so we need long (64-bit) arithmetic throughout.
  • -10^5 <= lower <= upper <= 10^5 --> The range bounds are relatively small, but the prefix sums themselves can be huge due to the element value range.

Approach 1: Brute Force

Intuition

Compute every possible range sum and check whether it falls within [lower, upper]. Prefix sums reduce each sum computation from O(n) to O(1), but we still enumerate all O(n^2) pairs.

Build a prefix sum array where prefix[i] stores the sum of nums[0..i-1]. Then the sum of any subarray nums[i..j] equals prefix[j+1] - prefix[i]. Now iterate over all pairs (i, j) with 0 <= i < j <= n and count how many satisfy lower <= prefix[j] - prefix[i] <= upper.

Algorithm

  1. Build a prefix sum array of length n+1 where prefix[0] = 0 and prefix[k] = prefix[k-1] + nums[k-1].
  2. For each pair (i, j) where 0 <= i < j <= n, compute prefix[j] - prefix[i].
  3. If the difference falls within [lower, upper], increment the count.
  4. Return the count.

Example Walkthrough

1Build prefix sums: prefix = [0, -2, 3, 2]. Check all pairs (i, j) where i < j
0
0
1
-2
2
3
3
2
1/7

Code

This is too slow for the given constraints. The next approach sorts the prefix sums while counting, so that for each prefix sum we can find how many earlier ones produce a valid difference without scanning them all.

Approach 2: Merge Sort (Divide and Conquer)

Intuition

Merge sort counts pairs during the merge step: both halves are already sorted at that point, which lets two pointers count valid pairs in O(n) instead of O(n^2).

We need to count pairs (i, j) where i < j and lower <= prefix[j] - prefix[i] <= upper. Rearranging, for a fixed j we need prefix sums from the left half that satisfy prefix[j] - upper <= prefix[i] <= prefix[j] - lower.

When merging two sorted halves, every element in the right half originally came after every element in the left half, so any left-right pairing satisfies i < j by construction. For each element in the right half, two pointers locate the range of valid elements in the sorted left half. Because the right half is also sorted, the query window [prefix[j] - upper, prefix[j] - lower] only shifts upward as j advances, so both pointers move forward monotonically and the total counting work is O(n) per merge level.

Algorithm

  1. Build a prefix sum array of length n+1 where prefix[0] = 0.
  2. Apply merge sort to the prefix sum array. During each merge step:
    • For each element prefix[j] in the right half, find the range of elements prefix[i] in the left half where prefix[j] - upper <= prefix[i] <= prefix[j] - lower. Use two pointers (lo and hi) on the left half.
    • Add (hi - lo) to the count for each such j.
    • Merge the two halves in sorted order as in standard merge sort.
  3. Return the total count accumulated across all merge steps.

Visualization and Code

Loading animation...

Merge sort reaches O(n log n) by interleaving counting with sorting. An alternative keeps the prefix sums in their original order and maintains a data structure that answers "how many values seen so far fall in range [a, b]" in O(log n).

Approach 3: Binary Indexed Tree (BIT) with Coordinate Compression

Intuition

Instead of divide and conquer, we can take an online approach. Process prefix sums from left to right. For each new prefix[j], count how many previously inserted prefix[i] values satisfy prefix[j] - upper <= prefix[i] <= prefix[j] - lower. This is a range count query on the values seen so far, and because we query before inserting prefix[j], only prefix[0] through prefix[j-1] are counted, which enforces i < j.

A Binary Indexed Tree (also called a Fenwick Tree) supports point updates and prefix sum queries in O(log n). To count values in a range [a, b], we compute prefixCount(b) - prefixCount(a-1). Prefix sums can have magnitude up to n * 2^31, so the BIT cannot be indexed by raw values. We use coordinate compression: collect all values we will ever query or insert, sort them, and map them to consecutive integers 1, 2, 3, ...

For each prefix[j], we insert prefix[j] and query the range [prefix[j] - upper, prefix[j] - lower]. So we collect all prefix sums and all the boundary values prefix[j] - upper and prefix[j] - lower, sort and deduplicate them, then map them to BIT indices.

Algorithm

  1. Build the prefix sum array.
  2. Collect all values needed for coordinate compression: every prefix[j], every prefix[j] - lower, and every prefix[j] - upper.
  3. Sort and deduplicate these values. Map each to an index 1..m.
  4. Initialize a BIT of size m.
  5. For j from 0 to n:
    • Query the BIT for the count of values in [prefix[j] - upper, prefix[j] - lower]. This counts valid prefix[i]'s already inserted.
    • Insert prefix[j] into the BIT by updating at its compressed index.
  6. Return the total count.

Example Walkthrough

1prefix = [0, -2, 3, 2]. Process left to right, query BIT before inserting
0
0
j
1
-2
2
3
3
2
1/7

Code