无意看到的LeetCode新题,不算太简单,大意是给一个数组,询问多少区间和在某个[L,R]之内。首先做出前缀和,将问题转为数组中多少A[j]-A[i] (j>i)在范围内。
有一种基于归并排序的做法,在每次归并完左右两个子区间后,当前区间两部分分别都已经排序完毕,基于有序这一点,扫描后半段区间,对于每个A[i] (i>=mid),目标区间即为[ A[i]-R, A[i]-L ], 对于有序数组来说,求出元素落在某一区间的个数直接就是upper_bound-lower_bound,事实上,这里我们只需要另外两个浮动于前半段区间的指针即可动态维护upper_bound和lower_bound,因为查询目标区间的两个端点是不断递增的。
递归边界条件(只有一个数)做一下特判。LeetCode题目本身也需要注意许多边边角角的trick,比如输入vector为空,元素加加减减溢出的情况,所以直接无脑long long就好。
题外话,不知为何本题设计上输出是一个int,按理如果卡O(n^2)的话,数据规模必然做到可以构造答案溢出int_max的。
1 class Solution { 2 public: 3 int lo,hi; 4 int ret=0; 5 void msort(vector<long long>& A,int x,int y,vector<long long>& T) { 6 if (y-x<=1) { 7 if (A[x]>=lo&&A[x]<=hi) ret++; 8 return; 9 } 10 int mid=x+(y-x)/2; 11 12 msort(A,x,mid,T); 13 msort(A,mid,y,T); 14 int p=x,q=mid,it=x; 15 int j1=x,j2=x; 16 for (int i=mid;i<y;i++) { 17 while (j1<mid&&A[i]-A[j1]>=lo) 18 j1++; 19 while (j2<mid&&A[i]-A[j2]>hi) 20 j2++; 21 ret+=j1-j2; 22 } 23 while (p<mid||q<y) { 24 if (q>=y||(p<mid&&A[p]<=A[q])) 25 T[it++]=A[p++]; 26 else 27 T[it++]=A[q++]; 28 } 29 for (int i=x; i<y; i++) 30 A[i]=T[i]; 31 } 32 int countRangeSum(vector<int>& nums, int lower, int upper) { 33 if (nums.size()==0) return 0; 34 ret=0; 35 lo=lower,hi=upper; 36 vector<long long> temp(nums.size(),0); 37 vector<long long> vec; 38 vec.push_back(nums[0]); 39 for (int i=1;i<nums.size();i++) 40 vec.push_back(nums[i]+vec[i-1]); 41 msort(vec,0,vec.size(),temp); 42 return ret; 43 } 44 };