leetcode算法题:区间和的个数

leetcode算法题327
链接:https://leetcode.cn/problems/count-of-range-sum

题目

给你一个整数数组 nums 以及两个整数 lower 和 upper 。求数组中,值位于范围 [lower, upper] (包含 lower 和 upper)之内的 区间和的个数 。

区间和 S(i, j) 表示在 nums 中,位置从 i 到 j 的元素之和,包含 i 和 j (i ≤ j)。

示例 1:
输入:nums = [-2,5,-1], lower = -2, upper = 2
输出:3
解释:存在三个区间:[0,0]、[2,2] 和 [0,2] ,对应的区间和分别是:-2 、-1 、2 。
示例 2:

输入:nums = [0], lower = 0, upper = 0
输出:1

解法

主要是利用归并排序的思路,在拆、合的过程中,进行计算

public static int countRangeSum(int[] nums, int lower, int upper) {
	if (nums == null || nums.length == 0) {
		return 0;
	}
	int N = nums.length;
	// 前缀和数组,方便你求区间[1,3]的和,直接使用[0,3]-[0,1],而不用提前遍历很多次,生成好各种区间的和
	long[] preSum = new long[N + 1];
	preSum[0] = nums[0];
	for (int i = 1; i < N; i++) {
		// 当前位置的累加和=之前位置累加和+当前位置值
		preSum[i] = preSum[i - 1] + nums[i];
	}
	return countRangeSumChai(preSum, 0, N - 1, lower, upper);
}

private static int countRangeSumChai(long[] preSum, int left, int right, int lower, int upper) {
	if (left == right) {
		if (preSum[left] >= lower && preSum[left] <= upper) {
			return 1;
		}
		return 0;
	}
	int mid = (left + right) / 2;
	return countRangeSumChai(preSum, left, mid, lower, upper) + countRangeSumChai(preSum, mid + 1, right, lower, upper) + countRangeSumHe(preSum, left, mid, right, lower, upper);
}

private static int countRangeSumHe(long[] preSum, int l, int mid, int r, int lower, int upper) {
	int res = 0;
	/**
	 * 假设lower=10,upper=40,前缀和[0,3]=100,求以3下标结尾的数组,有多个累加和,满足[10,40]
	 * 假设前缀和arr[1,3]满足,那么前缀和arr[0,3]-arr[0,1]也满足,这就要求arr[0,1]要满足[100-40,100-10]=[60,90]
	 */
	// 关键点:
	// 以i下标结尾的数组,有多少个前缀和满足
	// 这种写法会超出时间
	// for (int i = mid+1; i <= r; i++) {
	//     long min = preSum[i] - upper;
	//     long max = preSum[i] - lower;
	//     for (int j = l; j <= mid; j++) {
	//         if(preSum[j] >= min && preSum[j]<=max){
	//             res++;
	//         }
	//     }
	// }
	// 其实就是某个区间满足[lower,upper],不进行merge前,因为是有序的,再往前或往后就超出这个区间了
	int windowL = l;
	int windowR = l;
	for (int i = mid + 1; i <= r; i++) {
		long min = preSum[i] - upper;
		long max = preSum[i] - lower;
		while (windowL <= mid && preSum[windowL] < min) {
			windowL++;
		}
		while (windowR <= mid && preSum[windowR] <= max) {
			windowR++;
		}
		res += windowR - windowL;
	}

	long[] helps = new long[r - l + 1];
	int p1 = l;
	int p2 = mid + 1;
	int curIndex = 0;
	while (p1 <= mid && p2 <= r) {
		helps[curIndex++] = preSum[p1] < preSum[p2] ? preSum[p1++] : preSum[p2++];
	}
	while (p1 <= mid) {
		helps[curIndex++] = preSum[p1++];
	}
	while (p2 <= r) {
		helps[curIndex++] = preSum[p2++];
	}
	for (int i = 0; i < helps.length; i++) {
		preSum[l + i] = helps[i];
	}

	return res;
}

你可能感兴趣的:(数据结构与算法,算法,leetcode,数据结构)