[Hard] 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.
Thinking Process
- Prefix Sum Transformation: Convert subarray sum problem to prefix sum difference problem
- Divide & Conquer: Sort prefix sums, count pairs using two pointers
- Segment Tree: Maintain count of prefix sums, query range for each new prefix
- Clarify if the array is sorted, has negatives, or allows duplicates.
- Prefix sums answer range queries; hash maps answer pair/count queries.
- In-place tricks use swap/write index instead of extra arrays.
Common Approaches
Typical techniques for this pattern:
| Approach | Time | Space | Notes |
|---|---|---|---|
| Prefix sum | O(n) | O(n) | Range queries, subarray sum |
| Sort + scan | O(n log n) | O(1) | Intervals, meeting rooms |
| Kadane’s algorithm | O(n) | O(1) | Maximum subarray |
| Hash map counting (this problem) | O(n) | O(n) | Frequency, two-sum variants |
Examples
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 <= nums.length <= 10^5-2^31 <= nums[i] <= 2^31 - 1-10^5 <= lower <= upper <= 10^5
Common Mistakes
- Single element:
nums = [0],lower = 0,upper = 0→ return1 - All negative:
nums = [-2,-1],lower = -3,upper = -1→ count valid ranges - Large numbers: Use
long longto prevent overflow - Empty ranges: Handle cases where no valid ranges exist
-
Overflow prevention: Prefix sums can exceed
intrange - Integer overflow: Not using
long longfor prefix sumsclass Solution { public int countRangeSum(int[] nums, int lower, int upper) { int n = nums.length; long[]prefix(n + 1, 0); // prefix sum with 0 included for (int i = 0; i < n; i++) prefix[i + 1] = prefix[i] + nums[i]; long[]temp(n + 1); return divide = new return(prefix, 0, n, lower, upper, temp); } public int divide(long[] prefix, int left, int right, int lower, int upper, long[] temp) { if (left >= right) return 0; int mid = (left + right) / 2; int count = 0; count += divide(prefix, left, mid, lower, upper, temp); count += divide(prefix, mid + 1, right, lower, upper, temp); count += countCross(prefix, left, mid, right, lower, upper); merge(prefix, left, mid, right, temp); return count; } public int countCross(long[] prefix, int left, int mid, int right, int lower, int upper) { int count = 0; int wl = left, wr = left; for (int i = mid + 1; i <= right; i++) { long low = prefix[i] - upper; long high = prefix[i] - lower; while (wl <= mid && prefix[wl] < low) wl++; while (wr <= mid && prefix[wr] <= high) wr++; count += wr - wl; } return count; } public void merge(long[] prefix, int left, int mid, int right, long[] temp) { int i = left, j = mid + 1, k = left; while (i <= mid && j <= right) temp[k++] = (prefix[i] <= prefix[j]) ? prefix[i++] : prefix[j++]; while (i <= mid) temp[k++] = prefix[i++]; while (j <= right) temp[k++] = prefix[j++]; for (int i = left; i <= right; i++) prefix[i] = temp[i]; } } - Off-by-one errors: Incorrect prefix sum indexing
- Missing prefix[0]: Forgetting to include empty prefix (sum = 0)
- Wrong range: Confusing
prefix[j] - upperandprefix[j] - lower - Memory leaks: Not managing segment tree nodes properly (though solution doesn’t delete)
Related Problems
- LC 327: Count of Range Sum - This problem
- LC 315: Count of Smaller Numbers After Self - Similar divide & conquer approach
- LC 493: Reverse Pairs - Count pairs with condition
- LC 307: Range Sum Query - Mutable - Segment tree for range sum
- LC 303: Range Sum Query - Immutable - Prefix sum basics
Key Takeaways
- Prefix Sum Transformation: Convert subarray sum problem to prefix sum difference problem
- Range Condition:
lower <= prefix[j] - prefix[i] <= upperbecomesprefix[j] - upper <= prefix[i] <= prefix[j] - lower - Two Approaches:
- Divide & Conquer: Sort prefix sums, count pairs using two pointers
- Segment Tree: Maintain count of prefix sums, query range for each new prefix
- Dynamic Node Creation: Reduces memory for sparse segment trees
References
- LC 327: Count of Range Sum on LeetCode
- LeetCode Discuss — LC 327: Count of Range Sum
- LeetCode Editorial (may require premium)