20.11.7 leetcode327 区间和的个数
题目链接:https://leetcode-cn.com/problems/count-of-range-sum/
题意:给一个整型的数组,求数组内有多少区间的区间和位于[lower,upper]中。
分析:用前缀和数组来处理,这样区间(i,j)和就可以简单理解为pres[j]-pres[i]。一个比较简单的想法是将前缀和数组排序,然后从第一个当被减数做起,后面的与它差值在[lower,upper】之间的就是符合要求的,但有问题的是因为数组中存在负数,排序后可能前面的前缀和排到后面去了,会出现前面的前缀和减后面的这种无效情况。所以我们可以采用归并的思想,左半段和右半段分别排序,在做半段里面找被减数,右半段是减数。
class Solution { public: int countRangeSumRecursive(vector<long>& sum, int lower, int upper, int left, int right) { if (left == right) { return 0; } else { int mid = (left + right) / 2; int n1 = countRangeSumRecursive(sum, lower, upper, left, mid); int n2 = countRangeSumRecursive(sum, lower, upper, mid + 1, right); int ret = n1 + n2; // 首先统计下标对的数量 int i = left; int l = mid + 1; int r = mid + 1; while (i <= mid) { while (l <= right && sum[l] - sum[i] < lower) l++; while (r <= right && sum[r] - sum[i] <= upper) r++; ret += (r - l); i++; } // 随后合并两个排序数组 vector<int> sorted(right - left + 1); int p1 = left, p2 = mid + 1; int p = 0; while (p1 <= mid || p2 <= right) { if (p1 > mid) { sorted[p++] = sum[p2++]; } else if (p2 > right) { sorted[p++] = sum[p1++]; } else { if (sum[p1] < sum[p2]) { sorted[p++] = sum[p1++]; } else { sorted[p++] = sum[p2++]; } } } for (int i = 0; i < sorted.size(); i++) { sum[left + i] = sorted[i]; } return ret; } } int countRangeSum(vector<int>& nums, int lower, int upper) { long s = 0; vector<long> sum{0}; for(auto& v: nums) { s += v; sum.push_back(s); } return countRangeSumRecursive(sum, lower, upper, 0, sum.size() - 1); } };