Merge sort on prefix sums
Time O(n log n) Space O(n)Sort prefixes by merge sort; for each left-half prefix, the matching right-half prefixes form a contiguous window found with two moving pointers.
nums = [-2, 5, -1], lower = -2, upper = 2Step 1/4Prefix sums: 0, −2, 3, 2. A subarray sum is p[later] − p[earlier]; it must be between −2 and 2.
class Solution {
private int lower, upper;
public int countRangeSum(int[] nums, int lower, int upper) {
this.lower = lower;
this.upper = upper;
long[] prefix = new long[nums.length + 1];
for (int i = 0; i < nums.length; i++) prefix[i + 1] = prefix[i] + nums[i];
return sort(prefix, new long[prefix.length], 0, prefix.length - 1);
}
private int sort(long[] p, long[] tmp, int lo, int hi) {
if (lo >= hi) return 0;
int mid = (lo + hi) >>> 1;
int count = sort(p, tmp, lo, mid) + sort(p, tmp, mid + 1, hi);
int a = mid + 1, b = mid + 1;
for (int i = lo; i <= mid; i++) {
while (a <= hi && p[a] - p[i] < lower) a++;
while (b <= hi && p[b] - p[i] <= upper) b++;
count += b - a;
}
int i = lo, j = mid + 1, k = lo;
while (i <= mid || j <= hi) tmp[k++] = (j > hi || (i <= mid && p[i] <= p[j])) ? p[i++] : p[j++];
System.arraycopy(tmp, lo, p, lo, hi - lo + 1);
return count;
}
}Verdict: The classic divide-and-conquer count.