LeetCode327. 区间和的个数 - Java & Go - 归并排序

LeetCode327. 区间和的个数

LeetCode327. 区间和的个数
在这里插入图片描述

1 算法

  • 算法
    • 1.归并排序
    • 2.计算前缀和sums[i]表示[0, i)的元素之和
    • 3.对前缀和进行归并排序
      • 首先将数组分成两半,递归对两个子数组进行归并排序,并将返回结果保存
      • 这时两个子数组已经有序,可以统计这样的区间[x, y],x遍历左子数组,y遍历右子数组,求得sums[y] - sums[x]的值在[lower, upper]范围中的区间有多少个
      • 最后需要将两个子数组合并成一个有序的数组
  • 相似题目

2 Java

public int countRangeSum(int[] nums, int lower, int upper) {
    if (nums == null || nums.length == 0) {
        return 0;
    }
    
    long[] sums = new long[nums.length + 1];
    for (int i = 1; i <= nums.length; i++) {
        sums[i] = sums[i-1] + nums[i-1];
    }
    return countRangeSumRecursive(sums, lower, upper, 0, sums.length - 1);
}

private int countRangeSumRecursive(long[] sum, int lower, int upper, int left, int right) {
    if (left == right) {
        return 0;
    } else {
        int mid = (left + right) >> 1;
        int n1 = countRangeSumRecursive(sum, lower, upper, left, mid);
        int n2 = countRangeSumRecursive(sum, lower, upper, mid + 1, right);
        int result = n1 + n2;

        // 首先统计下标对的数量
        int l = mid + 1;
        int r = mid + 1;
        for (int i = left; i <= mid; i++) {
            while (l <= right && sum[l] - sum[i] < lower) {
                l++;
            }
            while (r <= right && sum[r] - sum[i] <= upper) {
                r++;
            }
            result += r - l;
        }

        // 随后合并两个排序数组
        // Arrays.sort(sum, left, right+1);
        int[] sorted = new int[right - left + 1];
        int p1 = left, p2 = mid + 1, i = 0;
        while (p1 <= mid || p2 <= right) {
            if (p1 > mid) {
                sorted[i++] = (int) sum[p2++];
            } else if (p2 > right) {
                sorted[i++] = (int) sum[p1++];
            } else {
                if (sum[p1] < sum[p2]) {
                    sorted[i++] = (int) sum[p1++];
                } else {
                    sorted[i++] = (int) sum[p2++];
                }
            }
        }
        System.arraycopy(sorted, 0, sum, left, sorted.length);
        return result;
    }
}

3 Go

func countRangeSum(nums []int, lower int, upper int) int {
	if nums == nil || len(nums) == 0 {
		return 0
	}

	sums := make([]int, len(nums) + 1)
	for i := 1; i <= len(nums); i++ {
		sums[i] = sums[i-1] + nums[i-1]
	}
	return countRangeSumRecursion(sums, lower, upper, 0, len(sums) - 1)
}

func countRangeSumRecursion(sums []int, lower, upper, left, right int) int {
	if left == right {
		return 0
	} else {
		mid := (left + right) >> 1
		n1 := countRangeSumRecursion(sums, lower, upper, left, mid)
		n2 := countRangeSumRecursion(sums, lower, upper, mid + 1, right)
		result := n1 + n2

		l, r := mid + 1, mid + 1
		for i := left; i <= mid; i++ {
			for l <= right && sums[l] - sums[i] < lower {
				l++
			}
			for r <= right && sums[r] - sums[i] <= upper {
				r++
			}
			result += r - l
		}

		sorted := make([]int, right - left + 1)
		p1, p2, i := left, mid + 1, 0
		for p1 <= mid || p2 <= right {
			if p1 > mid {
				sorted[i] = sums[p2]
				p2++
			} else if p2 > right {
				sorted[i] = sums[p1]
				p1++
			} else {
				if sums[p1] < sums[p2] {
					sorted[i] = sums[p1]
					p1++
				} else {
					sorted[i] = sums[p2]
					p2++
				}
			}
			i++
		}
		for k := 0; k < len(sorted); k++ {
			sums[left + k] = sorted[k]
		}
		return result
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值