327. 区间和的个数

题目描述

给定一个整数数组 nums 。区间和 S(i, j) 表示在 nums 中,位置从 i 到 j 的元素之和,包含 i 和 j (i ≤ j)。

请你以下标 i (0 <= i <= nums.length )为起点,元素个数逐次递增,计算子数组内的元素和。

当元素和落在范围 [lower, upper] (包含 lower 和 upper)之内时,记录子数组当前最末元素下标 j ,记作 有效 区间和 S(i, j) 。

求数组中,值位于范围 [lower, upper] (包含 lower 和 upper)之内的 有效 区间和的个数。

注意

  • 最直观的算法复杂度是 O(n2) ,请在此基础上优化你的算法。

示例:

输入:nums = [-2,5,-1], lower = -2, upper = 2,

输出:3

解释:

下标 i = 0 时,子数组 [-2]、[-2,5]、[-2,5,-1],对应元素和分别为 -2、3、2 ;其中 -2 和 2 落在范围
[lower = -2, upper = 2] 之间,因此记录有效区间和 S(0,0),S(0,2) 。 下标 i = 1 时,子数组
[5]、[5,-1] ,元素和 5、4 ;没有满足题意的有效区间和。 下标 i = 2 时,子数组 [-1] ,元素和 -1
;记录有效区间和 S(2,2) 。 故,共有 3 个有效区间和。

提示:

  • 0 <= nums.length <= 10^4

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/count-of-range-sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

官方题解
能看懂的题解
用的归并排序,前序和

class Solution {
    public int countRangeSum(int[] nums, int lower, int upper) {
        long[] sum = new long[nums.length+1];
        for(int i = 0;i < nums.length;++i){
            sum[i+1] = sum[i]+nums[i];
        }
        return helpCountRangeSum(sum,lower,upper,0,sum.length-1);
    }

    public static int helpCountRangeSum(long[] sum, int lower, int upper, int left, int right){
        if(left == right){
            return 0;
        }else{
            int mid = left + (right-left)/2;
            int n1 = helpCountRangeSum(sum,lower,upper,left,mid);
            int n2 = helpCountRangeSum(sum,lower,upper,mid+1,right);
            int res = n1 + n2;
            int index = left;
            int l = mid+1;
            int u = mid+1;
            while(index <= mid){
                while(l <= right && sum[l]-sum[index] < lower){
                    l++;
                }
                while(u <= right && sum[u]-sum[index] <= upper){
                    u++;
                }
                res += u-l;
                index++;
            }
            long[] temNum = new long[right-left+1];
            int lef = left;
            int rig = mid+1;
            int i = 0;
            while(i < temNum.length){
                if(lef > mid){
                    temNum[i++] = sum[rig++];
                }else if(rig > right){
                    temNum[i++] = sum[lef++];
                }else{
                    if(sum[lef] < sum[rig]){
                        temNum[i++] = sum[lef++];
                    }else{
                        temNum[i++] = sum[rig++];
                    }
                }
            }
            for(int j = 0;j < temNum.length;++j){
                sum[left+j] = temNum[j];
            }
            return res;
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值