zoukankan      html  css  js  c++  java
  • LeetCode 327. 区间和的个数

    地址  https://leetcode-cn.com/problems/count-of-range-sum/

    给定一个整数数组 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
    典型的连续空间求和模板
    Y总得模板更好 hh
    1 线段树

    C++ 代码

    struct SegNode {
        int lo, hi, add;
        SegNode* lchild, *rchild;
        SegNode(int left, int right): lo(left), hi(right), add(0), lchild(nullptr), rchild(nullptr) {}
    };
    
    class Solution {
    public:
        SegNode* build(int left, int right) {
            SegNode* node = new SegNode(left, right);
            if (left == right) {
                return node;
            }
            int mid = (left + right) / 2;
            node->lchild = build(left, mid);
            node->rchild = build(mid + 1, right);
            return node;
        }
    
        void insert(SegNode* root, int val) {
            root->add++;
            if (root->lo == root->hi) {
                return;
            }
            int mid = (root->lo + root->hi) / 2;
            if (val <= mid) {
                insert(root->lchild, val);
            }
            else {
                insert(root->rchild, val);
            }
        }
    
        int count(SegNode* root, int left, int right) const {
            if (left > root->hi || right < root->lo) {
                return 0;
            }
            if (left <= root->lo && root->hi <= right) {
                return root->add;
            }
            return count(root->lchild, left, right) + count(root->rchild, left, right);
        }
    
        int countRangeSum(vector<int>& nums, int lower, int upper) {
            long long sum = 0;
            vector<long long> preSum = {0};
            for (int v: nums) {
                sum += v;
                preSum.push_back(sum);
            }
    
            set<long long> allNumbers;
            for (long long x: preSum) {
                allNumbers.insert(x);
                allNumbers.insert(x - lower);
                allNumbers.insert(x - upper);
            }
            // 利用哈希表进行离散化
            unordered_map<long long, int> values;
            int idx = 0;
            for (long long x: allNumbers) {
                values[x] = idx;
                idx++;
            }
    
            SegNode* root = build(0, values.size() - 1);
            int ret = 0;
            for (long long x: preSum) {
                int left = values[x - upper], right = values[x - lower];
                ret += count(root, left, right);
                insert(root, values[x]);
            }
            return ret;
        }
    };
    
    
     

    算法2
    2树状数组

    C++ 代码

    class BIT {
    private:
        vector<int> tree;
        int n;
    
    public:
        BIT(int _n): n(_n), tree(_n + 1) {}
    
        static constexpr int lowbit(int x) {
            return x & (-x);
        }
    
        void update(int x, int d) {
            while (x <= n) {
                tree[x] += d;
                x += lowbit(x);
            }
        }
    
        int query(int x) const {
            int ans = 0;
            while (x) {
                ans += tree[x];
                x -= lowbit(x);
            }
            return ans;
        }
    };
    
    class Solution {
    public:
        int countRangeSum(vector<int>& nums, int lower, int upper) {
            long long sum = 0;
            vector<long long> preSum = {0};
            for (int v: nums) {
                sum += v;
                preSum.push_back(sum);
            }
    
            set<long long> allNumbers;
            for (long long x: preSum) {
                allNumbers.insert(x);
                allNumbers.insert(x - lower);
                allNumbers.insert(x - upper);
            }
            // 利用哈希表进行离散化
            unordered_map<long long, int> values;
            int idx = 0;
            for (long long x: allNumbers) {
                values[x] = idx;
                idx++;
            }
    
            int ret = 0;
            BIT bit(values.size());
            for (int i = 0; i < preSum.size(); i++) {
                int left = values[preSum[i] - upper], right = values[preSum[i] - lower];
                ret += bit.query(right + 1) - bit.query(left);
                bit.update(values[preSum[i]] + 1, 1);
            }
            return ret;
        }
    };
    
     
    作 者: itdef
    欢迎转帖 请保持文本完整并注明出处
    技术博客 http://www.cnblogs.com/itdef/
    B站算法视频题解
    https://space.bilibili.com/18508846
    qq 151435887
    gitee https://gitee.com/def/
    欢迎c c++ 算法爱好者 windows驱动爱好者 服务器程序员沟通交流
    如果觉得不错,欢迎点赞,你的鼓励就是我的动力
    阿里打赏 微信打赏
  • 相关阅读:
    免安装的tomcat双击startup.bat后窗口一闪而过
    打包发布项目
    CNN目标检测系列算法发展脉络简析——学习笔记(三):Fast R-CNN
    CNN目标检测系列算法发展脉络简析——学习笔记(二):R-CNN
    VisualSVN-5.1.5补丁原创发布
    PostSharp-4.3.22安装包_KeyGen发布
    VisualSVN-5.1.4补丁原创发布
    DotNetBar for Windows Forms 12.9.0.0_冰河之刃重打包版及制作Visual Studio C#项目模板文件详解
    DotNetBar for Windows Forms 12.7.0.10_冰河之刃重打包版原创发布-带官方示例程序版
    DotNetBar for Windows Forms 12.5.0.2_冰河之刃重打包版原创发布-带官方示例程序版
  • 原文地址:https://www.cnblogs.com/itdef/p/13941087.html
Copyright © 2011-2022 走看看