区间和的个数.采用归并排序和前缀和数组来解决(java)

265 篇文章 2 订阅
33 篇文章 0 订阅

区间和的个数.(LeetCode原题第327题)

给你一个整数数组 nums 以及两个整数 lower 和 upper 。求数组中,值位于范围 [lower, upper] (包含 lower 和 upper)之内的 区间和的个数 。
区间和 S(i, j) 表示在 nums 中,位置从 i 到 j 的元素之和,包含 i 和 j (i ≤ j)。

原题链接:https://leetcode.cn/problems/count-of-range-sum
具体演示案例,就不在举例了,可以打开链接去看。

解题思路

这个要求的是区间和的个数,我们这样解题:
1.首先把数组转换成前缀和数组,
2.根据前缀和数组,我们可以把问题转换为,[sum[i]-upper,sum[i]-lower]这个区间范围内的前缀和,(怎样理解这句话,假如,sum[17]就代表前17位数字和,减去sum[3],就表示4到17 的区间和,如果sum[3]在[sum[i]-upper,sum[i]-lower] 这个范围,那剩下的区间和就会满足在lower和upper之间。)
3.再用归并排序去分解成小任务去解决

这次我们先写主方法,把数组转换成前缀和数组

  public static int merge(int[]arr,int lower,int upper){
        if (arr == null || arr.length == 0){
            return 0;
        }
        //前缀和数组
        long[]sum = new long[arr.length];
        sum[0] = arr[0]; //第一个元素的前缀和等于自身
        //构造前缀和数组
        for (int i = 1; i < arr.length;i++){
            sum[i] = sum[i-1]+arr[i];
        }
        //递归方法时,我们这时要传入的是前缀和数组,已经不是之前的数组
        return process(sum,0,arr.length-1,lower,upper);
    }
    

递归方法

 private static int process(long[] arr, int L, int R, int lower, int upper) {
        //base case
        if (L == R){
            return arr[L] <= upper && arr[L] >= lower ? 1 : 0;
        }
        int M  = L + ((R - L) >> 1);
        //最后一行 每次执行的结果加上把两个数组合并时的数量就等于总数量
        return process(arr,L,M,lower,upper)+
                process(arr,M + 1,R,lower,upper)+
                mergeSort(arr,L,M,R,lower,upper);
    }

最后我们看合并的写法,也是归并排序的扩展.

 private static int mergeSort(long[] arr, int l, int m, int r, int lower, int upper) {
 		//现在是计算合并时,右边前缀和,在左边有多少符合要求的.
        int windowL = l; // 起步都是l
        int windowR = l;
        int ans = 0; //开始满足条件的个数为0
        for (int i = m + 1;i <= r;i++){
        //这个就是将问题转成成有多少满足在[sum[i]-upper,sum[i]-lower]这个区间范围内
            long up = arr[i] - lower; 
            long lo = arr[i] - upper;
            while(windowR <= m && arr[windowR] <= up){
            	//在范围内一直右移
                windowR++;
            }
            while (windowL <= m && arr[windowL] < lo){
            	//不满足范围的话左边界一直左移
                windowL++;
            }
            //计算满足条件的个数
            ans += windowR - windowL;
        }
        //这个下面就是正常的归并排序的合并过程
        int p1 = l;
        int p2 = m + 1;
        long[]help = new long[r - l + 1];
        int i = 0;
        while (p1 <= m && p2 <= r){
            help[i++] = arr[p1]<=arr[p2] ? arr[p1++] : arr[p2++];
        }
        while (p1<=m){
            help[i++] = arr[p1++];
        }
        while (p2<=r){
            help[i++] = arr[p2++];
        }
        for (i = 0; i < help.length;i++){
            arr[l+i] = help[i];
        }
        return ans;
    }

归并排序入门详解.不了解归并排序可以看这个

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值