327. Count of Range Sum


Given an integer array nums, 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 (i ≤ j), inclusive.

Note:
A naive algorithm of O(n2) is trivial. You MUST do better than that.

Example:

Input: nums = [-2,5,-1], lower = -2, upper = 2,
Output: 3
Explanation: The three ranges are : [0,0], [2,2], [0,2] and their respective sums are: -2, -1, 2.

方法1:presum + map

思路:

和之前的寻找sum k subarray一样,只是变成了找到一个sum in [lower, upper]的数量。那么如果不能assume都是正数的话, presum并不是一个有序数列,这个计数仍然只能通过全扫描来完成。为了优化,可以强行将presum sort,记录成一个map,这样每次可以用二分内置函数lower/upper_bound来找到范围。这样再用distance可以直接求算这两个iterator之间元素的距离。distance(lb, ub)用于set,accumulate + 自定义(operator+)的方式可以累加map::iterator之间的val。

易错点:

  1. sum - upper 是lower_bound, sum - lower 是upper_bound。
  2. distance(lb, ub)和accumulate(lb, ub, 0, )的使用。

Complexity

Time complexity: O(nlogn)
Space complexity: O(n)

class Solution {
public:
    int countRangeSum(vector<int>& nums, int lower, int upper) {
        map<long long, int> presum;
        presum[0] = 1;
        long long sum = 0;
        int res = 0;
        for (auto num: nums) {
            sum += num;
            auto lb = presum.lower_bound(sum - upper);
            auto ub = presum.upper_bound(sum - lower);
            res += accumulate(lb, ub, 0, [](int v, const map<long long, int>::value_type& pair){
            return v + pair.second;
    // if we want to sum the first item, change it to 
    // return v + pair.first;
});
            presum[sum] ++;
        }
        return res;
    }
};

方法2:merge sort

思路:

上面的方法用到了map来自动排序,这里只是实现了merge sort 来对presum vector进行排序。

class Solution {
public:
    int mergeSort(vector<long>& sum, int lower, int upper, int low, int high)
    {
        if(high-low <= 1) return 0;
        int mid = (low+high)/2, m = mid, n = mid, count =0;
        count =mergeSort(sum,lower,upper,low,mid) +mergeSort(sum,lower,upper,mid,high);
        for(int i = low;i < mid; ++i){
            auto m = lower_bound(sum.begin()+mid,sum.begin()+high,sum[i] + lower);
            auto n = upper_bound(sum.begin()+mid,sum.begin()+high,sum[i] + upper);
            count += n-m;
        }
        inplace_merge(sum.begin()+low, sum.begin()+mid, sum.begin()+high);
        return count;
    }
    int countRangeSum(vector<int>& nums, int lower, int upper) {
        int len = nums.size();
        vector<long> sum(len + 1, 0);
        for(int i =0; i< len; i++) sum[i+1] = sum[i]+nums[i];
        return mergeSort(sum, lower, upper, 0, len+1);
    }
};

不用upper和lower_bound的做法

class Solution {
public:
    int mergeSort(vector<long>& sum, int lower, int upper, int low, int high)
    {
        if(high-low <= 1) return 0;
        int mid = (low+high)/2, m = mid, n = mid, count =0;
        count = mergeSort(sum,lower,upper,low,mid) + mergeSort(sum,lower,upper,mid,high);
        for(int i =low; i< mid; i++)
        {
            while(m < high && sum[m] - sum[i] < lower) m++;
            while(n < high && sum[n] - sum[i] <= upper) n++;
            count += n - m;
        }
        inplace_merge(sum.begin()+low, sum.begin()+mid, sum.begin()+high);
        return count;
    }
 
    int countRangeSum(vector<int>& nums, int lower, int upper) {
        int len = nums.size();
        vector<long> sum(len + 1, 0);
        for(int i =0; i< len; i++) sum[i+1] = sum[i]+nums[i];
        return mergeSort(sum, lower, upper, 0, len+1);
    }
};

方法3: BIT / Fenwick Tree

hrwhisper: https://www.hrwhisper.me/leetcode-count-of-range-sum/
思路:

Fenwich Tree 所帮忙解决的是在logn时间内找到presum的范围。

typedef long long LL;
class FenwickTree {
	vector<int> sum_array;
	int n;
	inline int lowbit(int x) {
		return x & -x;
	}
 
public:
	FenwickTree(int n) :n(n), sum_array(n + 1, 0) {}
 
	void add(int x, int val) {
		while (x <= n) {
			sum_array[x] += val;
			x += lowbit(x);
		}
	}
 
	int sum(int x) {
		int res = 0;
		while (x > 0) {
			res += sum_array[x];
			x -= lowbit(x);
		}
		return res;
	}
};
 
class Solution {
public:
	int countRangeSum(vector<int>& nums, int lower, int upper) {
		if (nums.size() == 0) return 0;
		vector<LL> sum_array (nums.size() * 3,0);
		LL sum = 0;
		for (int i = 0; i < nums.size(); i++) {
			sum += nums[i];
			sum_array[i * 3] = sum;
			sum_array[i * 3 + 1] = sum + lower - 1;
			sum_array[i * 3 + 2] = sum + upper;
		}
		sum_array.push_back(upper);
		sum_array.push_back(lower - 1);
		unordered_map<LL, int> index;
		sort(sum_array.begin(), sum_array.end());
		auto end = unique(sum_array.begin(), sum_array.end());
		auto it = sum_array.begin();
		for (int i = 1; it != end;i++,it++) {
			index[*it] = i;
		}
		FenwickTree tree(index.size());
		int ans = 0;
		for (int i = nums.size() - 1; i >= 0; i--) {
			tree.add(index[sum],1);
			sum -= nums[i];
			ans += tree.sum(index[upper + sum]) - tree.sum(index[lower + sum -1]);
		}
		return ans;
	}
};

方法4: Segment Tree

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值