327. 区间和的个数

给定一个整数数组 nums,返回区间和在 [lower, upper] 之间的个数,包含 lower 和 upper。
区间和 S(i, j) 表示在 nums 中,位置从 i 到 j 的元素之和,包含 i 和 j (i ≤ j)。

说明:
最直观的算法复杂度是 O(n2) ,请在此基础上优化你的算法。

示例:

输入: nums = [-2,5,-1], lower = -2, upper = 2,
输出: 3
解释: 3个区间分别是: [0,0], [2,2], [0,2],它们表示的和分别为: -2, -1, 2。

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class Solution {
public:
    //前缀和 sum[i...j]=pre[j]-pre[i] c++ set是有序的
    int countRangeSum(vector<int>& nums, int lower, int upper) {
        vector<long> preSum;
        long sum = 0;
        for(int i=0;i<nums.size();i++){
            sum += nums[i];
            preSum.push_back(sum);
        }
        int res=0;
        multiset<long> pre;
        pre.insert(0);
        for(int i=0;i<preSum.size();i++){
            // if(preSum[i]>= lower &&  preSum[i]<=upper){
            //         res++;
            // }
            // for(int j=i+1;j<preSum.size();j++){
            //     //这里找preSum[i]的过程导致两层循环。
            //     //lower <= preSum[j]-preSum[i] <= upper
            //     //              preSum[j]-upper =< preSum[i] <= preSum[j]-lower
            //     //查找: preSum[i] 大于某个数,小于某个数的个数,若是有序数组,可以使用二分查找。
            //     //
            //     // if(preSum[j]-preSum[i]>=lower && preSum[j]-preSum[i]<=upper ){
            //     //     res++;
            //     // }
            // }
            //遇到的每一个i,都找他之前的(0-i-1)个数中 位于(当前数-upper)=< preSum[i]<=(当前-lower) 之间得数的个数
            //若是之前的0-i-1个数是有序的
            //那么如果S数组是  有序的  我们就可以通过两次二分查找计算出有多少个x满足条件(d2-d1):
            //第一次二分查找找出第一个大于等于 presum - upper 的位置d1;
            //第二次二分查找找出第一个大于 presum - lower 的位置d2。
            //如何快速保证每次(0-i-1)的前缀和数组都有序?将前(0-i-1)位置的数都存入multiset,利用红黑树
            auto low = pre.lower_bound(preSum[i]-upper);
            auto high = pre.upper_bound(preSum[i]-lower);
            res += distance(low,high);
            pre.insert(preSum[i]);
        }
        return res;
    }
};

  

二分查找

复制代码
class Solution {
public:
    //查找有序数组,第一个>=key(下限)的数
    int find_first_position(vector<long> presum,long key) {
        if(presum.size() == 0) return 0;
        int low = 0, high = presum.size()-1;
        if(presum[high] < key) return high+1;
        while(low <= high){
            int mid = low+(high-low)/2;
            if(presum[mid] < key) low = mid+1;
            else if(presum[mid] >= key) high = mid-1;    
        }
        return low;
    }
    //查找有序数组,查找第一个可以插入到>=key(上限))的位置,即第一个大于key
    int find_last_position(vector<long> presum,long key) {
        if(presum.size()==0) return 0;
        int low = 0, high = presum.size()-1;
        if(presum[high] <= key) return high+1;
        
        while(low <= high){
            int mid = low+(high-low)/2;
            if(presum[mid] <= key) low = mid+1;
            else if(presum[mid] > key) high = mid-1;    
        }
        return low;
    }
     void SetToArray(multiset<long> pre,vector<long>& presum) {
        for(auto it= pre.begin();it!=pre.end();it++){
            presum.push_back(*it);
        }
        return ;
    }
    //前缀和 sum[i...j]=pre[j]-pre[i] c++ set是有序的
    int countRangeSum(vector<int>& nums, int lower, int upper) {
        vector<long> preSum;
        long sum = 0;
        for(int i=0;i<nums.size();i++){
            sum += nums[i];
            preSum.push_back(sum);
        }
        int res=0;
        multiset<long> pre;
        vector<long> presum;
        for(int i=0;i<preSum.size();i++){
            //遇到的每一个i,都找他之前的(0-i-1)个数中 位于(当前数-upper)=< preSum[i]<=(当前-lower) 之间得数的个数
            //若是之前的0-i-1个数是有序的
            //那么如果S数组是  有序的  我们就可以通过两次二分查找计算出有多少个x满足条件(d2-d1):
            //第一次二分查找找出第一个大于等于 presum - upper 的位置d1;
            //第二次二分查找找出第一个大于 presum - lower 的位置d2。
            //如何快速保证每次(0-i-1)的前缀和数组都有序?将前(0-i-1)位置的数都存入multiset,利用红黑树
            if(preSum[i] <= upper && preSum[i] >= lower) res++;

            int lower_bound = find_first_position(presum,preSum[i]-upper);
            int upper_bound = find_last_position(presum,preSum[i]-lower);            
            res += max(upper_bound-lower_bound,0);
            presum.clear();
            pre.insert(preSum[i]);
            SetToArray(pre,presum);
        }
        return res;
    }
};
复制代码

 

posted on   wsw_seu  阅读(104)  评论(0编辑  收藏  举报

编辑推荐:
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
阅读排行:
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· 新年开篇:在本地部署DeepSeek大模型实现联网增强的AI应用
· Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(三):用.NET IoT库
· 【非技术】说说2024年我都干了些啥
历史上的今天:
2017-10-25 合并两个排序的链表
2017-10-25 游历魔法王国

导航

< 2025年1月 >
29 30 31 1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31 1
2 3 4 5 6 7 8
点击右上角即可分享
微信分享提示