思路解析
自测版源码
package com.bigdata.javabasic.leetcode.sort;
public class CountOfRangeSum {
public static int countSUMOfSubArrInRange(int[] arr, int lower, int upper){
long currentTime = System.currentTimeMillis();
if(arr == null || lower > upper) return 0;
//calculate preSum[]
long[] preSum = new long[arr.length];
preSum[0] = arr[0];
for(int i = 1; i < arr.length; i++){
preSum[i] = preSum[i - 1] + arr[i];
}
//! recursive entry
int count = countPreSumInRange(preSum, 0, preSum.length - 1, lower, upper);
System.out.println(System.currentTimeMillis() - currentTime);
return count;
}
public static int countPreSumInRange(long[] preSum, int L, int R, int lower, int upper){
//!check sum of arr[0:R] (preSum[R]) isInRange, true then 1, false then 0
if(L == R) return preSum[L] <= upper && preSum[L] >= lower ? 1 : 0;
//check sum of arr[preSumL+1:R] isInRange
//recursive
int mid = L + ((R-L)>>1);
return countPreSumInRange(preSum, L, mid, lower, upper)
+ countPreSumInRange(preSum, mid+1, R, lower, upper)
+ merge(preSum, L, R, lower, upper);
}
public static int merge(long[] preSum, int L, int R, int lower, int upper){
int count = 0;
int preSumL = L;
int preSumR = L;
int mid = L + ((R-L)>>1);
//calculate count of subArr in range
for(int i = mid + 1; i <= R; i++){ //! i from (mid + 1) to R
//!each preSum[i] has a new range for preSum[preSumRange]
long min = preSum[i] - upper;
long max = preSum[i] - lower;
//! <= max, then move preSumR
while(preSumR <= mid && preSum[preSumR] <= max) preSumR++;
//! <min, then move preSumL
while(preSumL <= mid && preSum[preSumL] < min) preSumL++;
count += preSumR - preSumL;
}
//merge preSum[]!
long[] help = new long[R-L+1];
int id = 0;
int h1 = L;
int h2 = mid + 1;
while(h1 <= mid && h2 <= R)
help[id++] = preSum[h1] < preSum[h2] ? preSum[h1++] : preSum[h2++];
while(h1 <= mid) help[id++] = preSum[h1++];
while(h2 <= R) help[id++] = preSum[h2++];
for(int i = 0; i < help.length; i++) preSum[L+i] = help[i];
return count;
}
public static int comparator(int[] arr, int lower, int upper){
long currentTime = System.currentTimeMillis();
if(arr == null) return 0;
int count = 0;
for(int i = 0; i < arr.length; i++){
int sum = 0;
for(int j = i; j < arr.length; j++){
sum += arr[j];
if(sum > upper) continue; //!
if(lower <= sum) count++;
}
}
System.out.println(System.currentTimeMillis() - currentTime);
return count;
}
public static void main(String[] args){
int testTime = 500;
int maxSize = 5000;
int maxValue = 100;
System.out.println("test begin!");
for(int i = 0; i < testTime; i++){
int[] arr1 = MergeSort.generateRandArray(maxSize, maxValue);
int[] arr2 = MergeSort.copyArray(arr1);
int count1 = countSUMOfSubArrInRange(arr1, 10, 50); //O(NlogN)
int count2 = comparator(arr2, 10, 50); //O(N^2)
if(count1 != count2){
System.out.println("test failed!");
System.out.println("accurate");
System.out.println(count2);
System.out.println("yours");
System.out.println(count1);
}
}
System.out.println("test pass!");
}
}
提交版源码
class Solution {
public int countRangeSum(int[] nums, int lower, int upper) {
if(nums == null || lower > upper) return 0;
//calculate preSum[]
long[] preSum = new long[nums.length];
preSum[0] = nums[0];
for(int i = 1; i < nums.length; i++){
preSum[i] = preSum[i - 1] + nums[i];
}
//! recursive entry
return countPreSumInRange(preSum, 0, preSum.length - 1, lower, upper);
}
public int countPreSumInRange(long[] preSum, int L, int R, int lower, int upper){
//!check sum of arr[0:R] (preSum[R]) isInRange, true then 1, false then 0
if(L == R) return preSum[L] <= upper && preSum[L] >= lower ? 1 : 0;
//check sum of arr[preSumL+1:R] isInRange
//recursive
int mid = L + ((R-L)>>1);
return countPreSumInRange(preSum, L, mid, lower, upper)
+ countPreSumInRange(preSum, mid+1, R, lower, upper)
+ merge(preSum, L, R, lower, upper);
}
public int merge(long[] preSum, int L, int R, int lower, int upper){
int count = 0;
int preSumL = L;
int preSumR = L;
int mid = L + ((R-L)>>1);
//calculate count of subArr in range
for(int i = mid + 1; i <= R; i++){ //! i from (mid + 1) to R
//!each preSum[i] has a new range for preSum[preSumRange]
long min = preSum[i] - upper;
long max = preSum[i] - lower;
//! <= max, then move preSumR
while(preSumR <= mid && preSum[preSumR] <= max) preSumR++;
//! <min, then move preSumL
while(preSumL <= mid && preSum[preSumL] < min) preSumL++;
count += preSumR - preSumL;
}
//merge preSum[]!
long[] help = new long[R-L+1];
int id = 0;
int h1 = L;
int h2 = mid + 1;
while(h1 <= mid && h2 <= R)
help[id++] = preSum[h1] < preSum[h2] ? preSum[h1++] : preSum[h2++];
while(h1 <= mid) help[id++] = preSum[h1++];
while(h2 <= R) help[id++] = preSum[h2++];
for(int i = 0; i < help.length; i++) preSum[L+i] = help[i];
return count;
}
}
视频讲解
对应 左程云算法体系班——class05 归并排序
老师的源码见:https://github.com/algorithmzuo/algorithmbasic2020/blob/master/src/class05/Code01_CountOfRangeSum.java