zoukankan      html  css  js  c++  java
  • 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。

    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;
        }
    };
  • 相关阅读:
    hdu1915
    2014年9月28日 18:35:01
    洛谷—— P1122 最大子树和
    洛谷——P1103 书本整理
    洛谷—— P2049 魔术棋子
    UVA_1575
    洛谷—— P2424 约数和
    中文乱码问题
    JSP标签
    include指令
  • 原文地址:https://www.cnblogs.com/wsw-seu/p/13873018.html
Copyright © 2011-2022 走看看