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),那么这为一组解,求总共有几组解。
方法一 Time Limit Exceeded ,直接暴力求解,时间复杂度为O(n^2),并且也不符合题意
public int countRangeSum2(int[] nums, int lower, int upper) {
long[] sum = new long[nums.length + 1];
if (nums.length == 0) return 0;
int res = 0;
for (int i = 0; i < nums.length; i++) {
sum[i + 1] = nums[i] + sum[i];
}
for (int i = 0; i < sum.length; i++) {
for (int j = i + 1; j <= sum.length; j++) {
long tmp = sum[j] - sum[i];
if (tmp <= upper && tmp >= lower) res++;
}
}
return res;
}
方法二:看了半天才明白, 这里我们的排序对象是前缀求和数组sum,我们有左数组a和右数组b,且a和b数组都是排好序的,在归并排序的合并a,b之前,我们可以用i遍历左数组a,j,k两个指针分别取在右数组b搜索,使得:
- sums[k] - sums[i] < lower
- sums[j] - sums[i] <= upper
那么此时,我们就找到了j-k个符合要求的子数组个数。
数组a,b在归并之前,sum的相对顺序没有改变,而且a和b也未曾见过面,是没有相减过的,所以拿b-a是非常合理的。
所以用到归并排序降低了算法复杂度,归并排序的复杂度是n*logn。
public int countRangeSum(int[] nums, int lower, int upper) {
int n = nums.length;
long[] sums = new long[n + 1];
for (int i = 0; i < n; ++i) sums[i + 1] = sums[i] + nums[i];
return countWhileMergeSort(sums, 0, n + 1, lower, upper);
}
private int countWhileMergeSort(long[] sums, int start, int end, int lower, int upper) {
if (end - start <= 1) return 0;
int mid = (start + end) / 2;
int count = countWhileMergeSort(sums, start, mid, lower, upper)
+ countWhileMergeSort(sums, mid, end, lower, upper);
int j = mid, k = mid, t = mid;
long[] cache = new long[end - start];
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;
}
System.arraycopy(cache, 0, sums, start, t - start);
return count;
}
https://discuss.leetcode.com/topic/33738/share-my-solution