Count of Range Sum(leetcode)

来源:互联网 发布:网络策划是做什么的 编辑:程序博客网 时间:2024/06/10 13:36

Count of Range Sum

  • Count of Range Sum
    • 题目
    • 题目解析
    • 解决办法
      • sum数数
      • 归并排序


题目

leetcode题目
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:
Given nums = [-2, 5, -1], lower = -2, upper = 2,
Return 3.
The three ranges are : [0, 0], [2, 2], [0, 2] and their respective sums are: -2, -1, 2.


题目解析

题目的要求就是求原数组的子数组个数,子数组满足“子数组的数之和在给定的范围[lower, upper]内”条件。
例子中,nums = [-2, 5, -1],子数组为

  1. [-2] => [0, 0]
  2. [5] => [1, 1]
  3. [-1] => [2, 2]
  4. [-2, 5] => [0, 1]
  5. [5, -1] => [1, 2]
  6. [-2, 5, -1] => [0, 2]

子数组的总和在[-2, 2]中的子数组为[-2][-1][-2, 5, -1],个数为3。


解决办法

1. sum数数

sums[i] = nums[0] + nums[1] + … + nums[i]
找到满足条件lower <= sums[j] - sums[i] <= upper的区间[i, j](i <= j),即我们需要找到满足sums[j] - upper <= sums[i] <= sums[j] - loweri的个数。
PS:函数distance(iterator start, iterator end),迭代器start可以通过某种方法到达end,函数distance返回的是start到end的个数。

class Solution {public:    int countRangeSum(vector<int>& nums, int lower, int upper) {        int res = 0;        long long sum = 0;        multiset<long long> sums;        sums.insert(0);        for (int i = 0; i < nums.size(); ++i) {            sum += nums[i];            res += distance(sums.lower_bound(sum - upper), sums.upper_bound(sum - lower));            sums.insert(sum);        }        return res;    }        };

2. 归并排序

将数组sums分为两部分:左半部left和右半部right。由于数组sums在构建的时候已经呈递增顺序,使得leftright已经排好序了。当我们遍历left时候,在right找到满足以下条件的j, k

  1. sums[j] - sums[i] > upperj是满足该不等式的第一个下标
  2. sums[k] - sums[i] >= lowerk是满足该不等式的第一个下标

那么在[lower, upper]之间的区间的个数是j - k

同时我们也需要另一个下标t,用来拷贝所有满足sums[t] < sums[i]到一个寄存器Cache中以完成混合排序的过程。

class Solution {public:    int countRangeSum(vector<int>& nums, int lower, int upper) {        int s = nums.size();        vector<long> sums(s + 1, 0);        for (int i = 0; i < nums.size(); ++i) {            sums[i + 1] = sums[i] + nums[i];        }        return countAndMergeSort(sums, 0, sums.size(), lower, upper);    }    int countAndMergeSort(vector<long> &sums, int start, int end, int lower, int upper) {        if (end - start <= 1) return 0;        int mid = start + (end - start) / 2;        int count = countAndMergeSort(sums, start, mid, lower, upper) + countAndMergeSort(sums, mid, end, lower, upper);        int j = mid;        int k = mid;        int t = mid;        vector<int> cache(end - start, 0);        for (int i = start, r = 0; i < mid; i++, r++) {            while (k < end && sums[k] - sums[i] < lower) k++;            while (j < end && sums[j] - sums[i] <= upper) j++;            while (t < end && sums[t] < sums[i]) cache[r++] = sums[t++];            cache[r] = sums[i];            count += j - k;        }        copy(cache.begin(), cache.begin() + t - start, sums.begin() + start);        return count;    }};
原创粉丝点击