BIT-Count of Range Sum

2019-12-17 18:56:56

问题描述

问题求解

本题个人感觉还是很有难度的,主要的难点在于如何将题目转化为bit计数问题。

首先构建一个presum数组,这个没有问题。

需要对于任意一个j,我们需要知道的是presum[i]的个数使得 lower <= presum[j] - presum[i] <= upper。

上述等式等价于求符合 presum[j] - upper <= presum[i] <= presum[j] - lower 的presum[i]的个数。

看到这个是不是有点眼熟了呢,求满足某个条件的区间的个数,这个和逆序数问题是完全一致的,只是在那个问题里我们只有一个上界,这里多了一个下界罢了。

同逆序数的解法,这里我们可以使用树状数组来进行求解。

    public int countRangeSum(int[] nums, int lower, int upper) {
        if (nums.length == 0) return 0;
        int res = 0;
        int n = nums.length;
        long[] presum = new long[n];
        presum [0] = nums[0];
        for (int i = 1; i < n; i++) presum[i] = presum[i - 1] + nums[i];
        long[] copy = Arrays.copyOf(presum, n);
        Arrays.sort(copy);
        TreeMap<Long, Integer> map = new TreeMap<>();
        int rank = 0;
        for (int i = 0; i < n; i++) {
            if (i == 0 || copy[i] != copy[i - 1]) {
                map.put(copy[i], ++rank);
            }
        }
        int[] bit = new int[map.size() + 1];
        for (int i = 0; i < n; i++) {
            if (presum[i] >= lower && presum[i] <= upper) res += 1;
            Long r = map.floorKey(presum[i] - lower);
            Long l = map.ceilingKey(presum[i] - upper);
            if (l != null && r != null) res += query(bit, map.get(r)) - query(bit, map.get(l) - 1); 
            update(bit, map.get(presum[i]));
        }
        return res;
    }
    
    private void update(int[] bit, int idx) {
        for (int i = idx; i < bit.length; i += i & -i) {
            bit[i] += 1;
        }
    }
    
    private int query(int[] bit, int idx) {
        int res = 0; 
        for (int i = idx; i > 0; i -= i & -i) {
            res += bit[i];
        }
        return res;
    }

  

原文地址:https://www.cnblogs.com/hyserendipity/p/12056251.html