327. 区间和的个数

今天的题目还是看了一阵子(😅😅)

!我是链接

在这里插入图片描述
意思是任意子区间内所有元素的和要在 lowerupper 之间,可以取等
所以题目中 [0,0] [2,2] 都指向各自位置的元素,[0,2] 就是从第0个元素 一直加到 第2 个元素 等于 2 . 所以这就是为什么输出是3.

  • 先写了个暴力:
class Solution {
public:
    int countRangeSum(vector<int>& nums, int lower, int upper) {
        int  count=0;
        long sum=0; //数据相加会超过int数据范围
        for(int i=0;i<nums.size();++i){
            if(nums[i]>=lower&&nums[i]<=upper){
                count++;
            }
            sum=nums[i];
            for(int j=i+1;j<nums.size();++j){
                sum+=nums[j];
                if(sum>=lower&&sum<=upper){
                    count++;
                }
            }
        }
        return count;
    }
};

很平常的超过时间限制了。

使用前缀和依旧死得很惨。。。。

class Solution {
public:
    int countRangeSum(vector<int>& nums, int lower, int upper) {
        if(nums.size()==0)
            return 0;
        int  count=0;
        long sum=0;
        vector<long> any_sum(nums.size());
        any_sum[0]=nums[0];
        cout<<any_sum[0]<<" ";
        for(int i=1;i<nums.size();i++){
            any_sum[i]=any_sum[i-1]+nums[i];
            cout<<any_sum[i]<<" ";
        }
        // if(sum>=lower&&sum<=upper)count++;
            // cout<<"\n"<<sum<<":";
                // cout<<"("<<sum<<")"<<" ";
        for(int i=any_sum.size()-1;i>=0;--i){
            if(any_sum[i]>=lower&&any_sum[i]<=upper)count++;
            for(int j=i-1;j>=0;j--){
                sum=any_sum[i]-any_sum[j];
                if(sum>=lower&&sum<=upper)count++;
            }
        }
        return count;
    }
};

看题解啦··············我是链接

class Solution {
public:
    int countRangeSum(vector<int>& nums, int lower, int upper) {
        int n = nums.size();
        vector<int64_t> S(n+1,0);
        vector<int64_t> assist(n+1,0);
        for(int i=1;i<=n;i++)S[i] = S[i-1] + nums[i-1];
        
        return merge(S,assist,0,n,lower,upper);
        
    }
    int merge(vector<int64_t> &S,vector<int64_t> &assist,int L,int R,int low,int up){
        
        if(L >= R) return 0;
    
        int cnt = 0;
        int M = L + (R-L)/2;
        cnt += merge(S,assist,L,M,low,up);
        cnt += merge(S,assist,M+1,R,low,up);
        int Left = L;
        int Upper = M+1,Lower = M+1;
        while(Left <= M){
            while(Lower <= R && S[Lower] - S[Left] < low)Lower++;
            while(Upper <= R && S[Upper] - S[Left] <= up)Upper++;

            cnt += Upper - Lower;
            Left++;
        }
        //以下为归并排序中归并过程
        Left = L;
        int Right = M + 1;mmp
        int pos = L;
        while(Left<= M || Right <= R){
            if(Left > M)assist[pos] = S[Right++];
            if(Right > R && Left <= M)assist[pos] = S[Left++];
            
            if(Left <= M && Right <= R){
                if(S[Left] <= S[Right])assist[pos] = S[Left++];
                else assist[pos] = S[Right++];
            }
            pos++;     
        }
        for(int i=L;i<=R;i++)S[i] = assist[i];
        return cnt;
    }
};

作者的意思是,利用 前缀和归并排序
1.前缀和先求出所有的相应位置的和
2.归并排序会把数组分成若干区间,让后两两相比较排序,从底向上的排序。
3.根据题目要求 成立条件就变成了:lower<=s[i]-s[j]<=upper

在这里插入图片描述
作者作图表示的是归并最后一层

在这里插入图片描述

这一块是关键。
根据最后的成立条件:lower<=s[i]-s[j]<=upper ( i >j )
只要分组后的左边某个之和作为基准
右边能够使得

- s[i0]-s[j]>=lower
- s[i1]-s[j]<=upper
那为什么 成立条件集合是这个家伙呢????
cnt += Upper - Lower
首先我们知道这是被排过序了(单看一边)的吧(图中是最后一层归并了)
回想一下只使用前缀和时,我们在左边确定一个锚点,从锚点的下一个位置开始一个一个的减,若是满足 lower<=sum<=upper 咱们就加上。
在归并中 ,我们直接确定 当 left=i有序数组下 最小的满足 >=lower 的位置最大满足 <=upper 的位置,两者相减得到的长度表示,该区间内的元素都满足 lower<= sum<=upper
好吧,剩下的就时归并排序的样子了,多敲敲就行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值