区间和的个数

区间和的个数

题目描述

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

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

示例 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

提示:
1 < = n u m s . l e n g t h < = 1 0 5 1 <= nums.length <= 10^{5} 1<=nums.length<=105

− 2 31 = n u m s [ i ] < = 2 31 − 1 -2^{31} = nums[i] <= 2^{31}-1 231=nums[i]<=2311

− 1 0 5 < = l o w e r < = u p p e r < = 1 0 5 -10^{5} <= lower <= upper <= 10^{5} 105<=lower<=upper<=105

  • 题目数据保证答案是一个 32 位 的整数

题目分析

1、区间和,想到前缀和

2、区间和表示的是两两前缀和相减,然后判断是否满足区间。正常来做的化是双层for循环。但是数据规模给的是10的5次幂,因此算法的时间复杂度只能为O(nlogn)。因此作比较的就只能将时间复杂度缩写,归并排序的方式正好可以满足。

代码

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

    private int process(long[] sum, int L, int R, int lower, int upper) {
        if(L==R){
            return sum[L] >=lower && sum[R] <= upper?1:0;
        }
        int M = L +((R-L)>>1);
        return process(sum,L,M,lower,upper)+process(sum,M+1,R,lower,upper)+merge(sum,L,M,R,lower,upper);
    }

    private int merge(long[] sum, int l, int m, int r, int lower, int upper) {
        int WindowL = l;
        int WindowR = l;
        int index = m+1;
        int ans = 0;
        while (index<=r){
            long max = sum[index]-lower;
            long min = sum[index]-upper;
            while(WindowR<=m && sum[WindowR]<=max){
                WindowR++;
            }
            while (WindowL<= m && sum[WindowL]<min){
                WindowL++;
            }
            ans += WindowR-WindowL;
            index++;
        }
        
        int p1= l;
        int p2 = m+1;
        long[] help = new long[r-l+1];
        int cur = 0;
        while (p1<= m && p2<=r){
            help[cur++] = sum[p1]<sum[p2]?sum[p1++]:sum[p2++];
        }
        while (p1<=m){
            help[cur++] = sum[p1++];
        }
        while (p2<=r){
            help[cur++] = sum[p2++];
        }
        for (int i = 0; i < help.length; i++) {
            sum[l+i] = help[i];
        }
        return ans;
    }

总结

  1. 归并排序步骤:结束条件L=R,从左、右、合并中获取所需结果
  2. 别忘记中间每个过程,左右都是已经排好序了的
  • 20
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值