Count of Range Sum

hard array binary search divide and conquer merge sort

Problem

Return the number of subarrays whose sum lies in [lower, upper]. Use prefix sums P so that S(i, j) = P[j+1] − P[i]; count pairs (i, j) with lower ≤ P[j] − P[i] ≤ upper.

Inputnums = [-2, 5, -1], lower = -2, upper = 2
Output3
Subarrays [−2], [−1], and [−2, 5, −1] (sum 2) lie in [−2, 2].

def count_range_sum(nums, lower, upper):
    pre = [0]
    for x in nums: pre.append(pre[-1] + x)
    def merge_count(l, r):
        if r - l <= 1: return 0
        m = (l + r) // 2
        cnt = merge_count(l, m) + merge_count(m, r)
        j = k = m
        for i in range(l, m):
            while j < r and pre[j] - pre[i] < lower: j += 1
            while k < r and pre[k] - pre[i] <= upper: k += 1
            cnt += k - j
        pre[l:r] = sorted(pre[l:r])
        return cnt
    return merge_count(0, len(pre))
function countRangeSum(nums, lower, upper) {
  const pre = [0];
  for (const x of nums) pre.push(pre[pre.length - 1] + x);
  function mergeCount(l, r) {
    if (r - l <= 1) return 0;
    const m = (l + r) >> 1;
    let cnt = mergeCount(l, m) + mergeCount(m, r);
    let j = m, k = m;
    for (let i = l; i < m; i++) {
      while (j < r && pre[j] - pre[i] < lower) j++;
      while (k < r && pre[k] - pre[i] <= upper) k++;
      cnt += k - j;
    }
    const part = pre.slice(l, r).sort((a, b) => a - b);
    for (let i = 0; i < part.length; i++) pre[l + i] = part[i];
    return cnt;
  }
  return mergeCount(0, pre.length);
}
class Solution {
    long[] pre; int lo, hi;
    public int countRangeSum(int[] nums, int lower, int upper) {
        pre = new long[nums.length + 1];
        for (int i = 0; i < nums.length; i++) pre[i + 1] = pre[i] + nums[i];
        lo = lower; hi = upper;
        return merge(0, pre.length);
    }
    int merge(int l, int r) {
        if (r - l <= 1) return 0;
        int m = (l + r) / 2;
        int cnt = merge(l, m) + merge(m, r);
        int j = m, k = m;
        for (int i = l; i < m; i++) {
            while (j < r && pre[j] - pre[i] < lo) j++;
            while (k < r && pre[k] - pre[i] <= hi) k++;
            cnt += k - j;
        }
        long[] part = Arrays.copyOfRange(pre, l, r);
        Arrays.sort(part);
        System.arraycopy(part, 0, pre, l, part.length);
        return cnt;
    }
}
vector<long> pre; int lo, hi;
int merge_(int l, int r) {
    if (r - l <= 1) return 0;
    int m = (l + r) / 2;
    int cnt = merge_(l, m) + merge_(m, r);
    int j = m, k = m;
    for (int i = l; i < m; i++) {
        while (j < r && pre[j] - pre[i] < lo) j++;
        while (k < r && pre[k] - pre[i] <= hi) k++;
        cnt += k - j;
    }
    sort(pre.begin() + l, pre.begin() + r);
    return cnt;
}
int countRangeSum(vector<int>& nums, int lower, int upper) {
    pre.assign(nums.size() + 1, 0);
    for (int i = 0; i < (int)nums.size(); i++) pre[i + 1] = pre[i] + nums[i];
    lo = lower; hi = upper;
    return merge_(0, pre.size());
}
Time: O(n log n) Space: O(n)