【Leetcode327】区间和的个数
题目描述
给你一个整数数组 \(nums\) 以及两个整数 \(lower\) 和 \(upper\) 。求数组中,值位于范围 \([lower, upper]\) (包含 \(lower\) 和 \(upper\))之内的区间和的个数 。
区间和 \(S(i, j)\) 表示在 \(nums\) 中,位置从 \(i\) 到 \(j\) 的元素之和,包含 \(i\) 和 \(j\) \((i \le j)\)。
分析
\(O(n^2)\)做法
由区间和很容易想到前缀和做法,于是处理出前缀和数组sum[i],枚举区间的开头和结尾进行判断即可。
\(O(n\log n)\)做法
只枚举区间的结尾,查询以此为结尾的区间中有多少个符合条件的区间。
由前缀和公式得 \(lower \le sum[end] - sum[start] \le upper\) ,则有 \(sum[end]-upper \le sum[start] \le sum[end] - lower\) ,即对sum[start]进行区间查询,得到满足条件的start个数有多少个。
用权值线段树来维护 \(sum[start]\) ,并且由于该题 \(nums[i]\) 数据范围较大,但 \(nums\) 数组个数较少,可以使用离散化方法对其进行哈希处理。哈希过程中使用 upper_bound 函数,需要注意查询上界的处理。
class Solution {
public:
int tree[400010]={0},l_of_nums=0,k;
long long sum[100005]={0},b[100005]={0};
int hash(long long number){
return lower_bound(sum,sum+k,number)-sum;
}
void change(int from,int to,int cur_node,int tar_index){//对 tar_index 位置+1
//from-to:当前节点值代表这个区间范围的和
//cur_node:当前节点在树中的标号
//tar_index:要修改的区间点值
if(from==to){
tree[cur_node]++;
return;
}
int mid=(from+to)>>1;
if(mid<tar_index)change(mid+1,to,cur_node<<1|1,tar_index);
else change(from,mid,cur_node<<1,tar_index);
tree[cur_node]=tree[cur_node<<1]+tree[cur_node<<1|1];
}
int query(int from,int to,int cur_node,int lower,int upper){
if(from>=lower && to<=upper)return tree[cur_node];
int query_ans=0,mid=(from+to)>>1;
if(lower<=mid)query_ans+=query(from,mid,cur_node<<1,lower,upper);
if(upper>mid)query_ans+=query(mid+1,to,cur_node<<1|1,lower,upper);
return query_ans;
}
int countRangeSum(vector<int>& nums, int lower, int upper) {
l_of_nums=nums.size();
sum[0]=0;
for(int i=0;i<l_of_nums;i++)
{
sum[i+1]=sum[i]+nums[i];
b[i]=sum[i+1];
} //前缀和
k=l_of_nums+1;
sum[k++]=-1e15;
sum[k++]=1e15;
sort(sum,sum+k); //sum[i]排序 离散化
k=unique(sum,sum+k)-sum; //得到有k个不同的sum[i]数值 去重[0,k-1]
int ans=0;
change(0,k-1,1,hash(0));
for(int end=0;end<l_of_nums;end++) //枚举b[end]
{
int l=hash(b[end]-upper);
int r=hash(b[end]-lower);//>=
if (sum[r]>b[end]-lower) r--;
int cnt=query(0,k-1,1,l,r);
//cout<<end<<" "<<b[end]<<" "<<cnt<<endl;
ans+=cnt; //cnt:使得lower<sum[end]-sum[start]<upper的start个数,start<end,即 sum[end]-upper<sum[start]<sum[end]-lower
change(0,k-1,1,hash(b[end]));
}
return ans;
}
};
\```