欢迎您访问365答案网,请分享给你的朋友!
生活常识 学习资料

[归并排序]leetcode327:区间和的个数

时间:2023-07-30

题目:


题解:

思路:归并排序

1)对于区间和的快速求解需要使用前缀和,由于 a 中的元素有正有负,所以前缀和数组不是单调递增的,我们可以对前缀和数组进行归并排序,顺便计算区间和的个数,求 pre[j]-pre[i]∈[lower,upper] 的 (i,j) 的个数。2)思考如何利用两个升序数组n1,n2求出n2[j]-n1[i]∈[lower,upper]?
3)在解决这一问题后,原问题就迎刃而解了:我们采用归并排序的方式,能够得到左右两个数组排序后的形式,以及对应的下标对数量。对于原数组而言,若要找出全部的下标对数量,只需要再额外找出左端点在左侧数组,同时右端点在右侧数组的下标对数量,而这正是我们此前讨论的问题。


代码如下:

const int N = 1e5+10;using LL = long long;class Solution {public: // 思路:归并排序,在两个升序数组中寻找下标对的区间和在[lower,upper]之间。每次统计第二个区间的n2[l]>=n1[0]+lower,n2[r]>n1[0]+uperr,这样的话[l,r)范围内的区间和都在[lower,upper]之间了。由于n1是递增的,因此l,r只能向右移动才能进行统计了。 LL pre[N],b[N]; int countRangeSum(vector& a, int lower, int upper) { int n=a.size(); memset(pre,0,sizeof pre),memset(b,0,sizeof b); // 预处理前缀和数组 for(int i=1;i<=n;++i)pre[i]=pre[i-1]+a[i-1]; return merge(lower,upper,0,n); } int merge(int lower,int upper,int l,int r){ if(l>=r)return 0; // 1.确定分界点,递归处理左右两段 int mid=(l+r)>>1; int res=merge(lower,upper,l,mid)+merge(lower,upper,mid+1,r); // 2.统计下标对的数量 int i=l,_l=mid+1,_r=mid+1; while(i<=mid) { // 直到pre[_l]-pre[i]>=lower为止;直到pre[_r]-pre[i]>upper为止;这样区间[_l,_r)满足情况了 while(_l<=r&&pre[_l]-pre[i]mid)b[k++]=pre[j++]; else if(j>r)b[k++]=pre[i++]; else{ if(pre[i]

Copyright © 2016-2020 www.365daan.com All Rights Reserved. 365答案网 版权所有 备案号:

部分内容来自互联网,版权归原作者所有,如有冒犯请联系我们,我们将在三个工作时内妥善处理。