LeetCode307.区域和检索 - 数组可修改

本文介绍了如何使用树状数组(Segment Tree)解决LeetCode问题307,通过维护前缀和并控制时间复杂度,实现数组的区间和查询和动态修改操作。提供了C++代码示例,并总结了树状数组的基本概念。

LeetCode307.区域和检索 - 数组可修改

树状数组板子题,维护前缀和,控制时间复杂度

代码附上(注释)

树状数组知识点讲解看我这篇文章树状数组

class NumArray {
private:
    vector<int> tree; //树状数组
    vector<int> &nums;

    int lowBit(int x) {
        return x & -x;
    }

    void add(int index, int val) {
        while (index < tree.size()) {
            tree[index] += val;
            index += lowBit(index);//index是动态更新的
        }
    }

    int query(int index) { //index前缀和
        int sum = 0;
        while (index > 0) {
            sum += tree[index];
            index -= lowBit(index);//index是动态更新的
        }
        return sum;
    }

public:
    NumArray(vector<int>& nums) : tree(nums.size() + 1), nums(nums) {
        for (int i = 0; i < nums.size(); i++) {
            add(i + 1, nums[i]); //因为lowbit下标从1开始 树状数组初始化
        }
    }

    void update(int index, int val) {
        add(index + 1, val - nums[index]); //树状数组维护
        nums[index] = val;
    }

    int sumRange(int left, int right) {
        return query(right + 1) - query(left);
    }
};




觉得文章有用,点个赞,点个收藏,支持一下

<think>嗯,用户想比较线段树树状数组的区别应用场景。这个问题很专业,看来用户正在学习数据结构或者准备算法竞赛。从引用内容看,用户可能已经接触过树状数组的代码实现(引用34),但对两种数据结构的整体对比还不够清晰。 用户提供的引用材料很有价值:引用1提到树状数组的局限性;引用2直接比较了两种结构的开发效率;引用34展示了树状数组的代码模板。这些正好能支撑我的回答框架。 需要重点突出几个维度:原理差异(树状数组基于二进制索引,线段树是二叉树)、功能范围(区间更新/查询的复杂度差异)、代码复杂度(树状数组短小精悍)。特别要强调引用2的观点:能用树状数组解决的问题优先用,就像"杀鸡不用宰牛刀"。 用户似乎更关注实用场景而非理论,所以回答要侧重应用案例。比如:树状数组适合动态前缀(引用4的题目),线段树适合区间最值(引用1的RMQ问题)。还要提醒树状数组的局限性,比如不直接支持区间最大值查询(引用1)。 最后考虑设计的问题要引导用户深入思考:性能分析场景能巩固基础,离散化应用是常见考点,而对比其他结构(如分块)能帮助建立知识体系。这样用户就能根据实际需求选择了。</think>以下是线段树与树状数组的核心区别及适用场景分析,结合引用资料进行说明: --- ### **一、底层原理对比** | **特性** | **树状数组 (Fenwick Tree)** | **线段树 (Segment Tree)** | |------------------|------------------------------------------|--------------------------------------| | **结构** | 基于**二进制索引**(`lowbit`操作) | 基于**二叉树**(完全二叉树结构) | | **存储空间** | $O(n)$(原数组大小) | $O(4n)$(需开4倍空间) | | **代码复杂度** | 极简(约20行代码)[^2] | 较高(递归建树/更新/查询) | --- ### **二、功能支持对比** | **操作** | 树状数组 | 线段树 | **说明** | |------------------|----------|--------|----------| | **单点修改** | ✅ $O(\log n)$ | ✅ $O(\log n)$ | 两者均高效 | | **前缀查询** | ✅ $O(\log n)$ | ✅ $O(\log n)$ | 树状数组更简洁[^4] | | **任意区间** | ✅(需两次查询) | ✅ $O(\log n)$ | 树状数组需计算`query(r)-query(l-1)` | | **区间最值** | ❌ | ✅ $O(\log n)$ | 树状数组需改造且效率低[^1] | | **区间修改** | ❌(需结合差分) | ✅ $O(\log n)$ | 树状数组需额外处理[^3] | | **离散化支持** | ✅ | ✅ | 两者均适用无穷坐标场景[^1] | --- ### **三、适用场景分析** #### **优先使用树状数组的场景** 1. **动态前缀问题** - 如实时更新数组元素并快速计算前缀(引用4的模板题)[^4]。 - 例:股票价格波动统计、实时数据流分析。 2. **单点修改+区间求** - 树状数组代码量少、调试简单(杀鸡不用宰牛刀)[^2]。 3. **内存敏感场景** - 空间复杂度$O(n)$ vs 线段树$O(4n)$,数据量大时优势明显。 #### **优先使用线段树的场景** 1. **复杂区间操作** - 区间最大值/最小值(RMQ问题)[^1]、区间修改(如批量加值)。 - 例:查询某时间段内的最高温度。 2. **自定义区间合并** - 支持自定义合并函数(如区间GCD、覆盖问题)[^1]。 3. **多维问题扩展** - 二维平面操作(如矩阵区域)时线段树更易扩展。 --- ### **四、典型问题示例** 1. **树状数组适用** - LeetCode 307. 区域检索 - 数组修改 ```python # 树状数组实现(引用4的简化版) def update(index, val): # 单点修改 while index <= n: tree[index] += val index += index & -index def query(index): # 前缀查询 res = 0 while index: res += tree[index] index -= index & -index ``` 2. **线段树适用** - LeetCode 732. 我的日程安排表 III(区间覆盖计数) ```python # 线段树区间更新(Lazy标记) def update(l, r, val, node=1, nl=1, nr=n): if l > nr or r < nl: return if l <= nl and nr <= r: tree[node] += val lazy[node] += val return push_down(node) # 下推Lazy标记 mid = (nl + nr) // 2 update(l, r, val, node*2, nl, mid) update(l, r, val, node*2+1, mid+1, nr) tree[node] = max(tree[node*2], tree[node*2+1]) ``` --- ### **总结选择策略** | **场景** | **推荐结构** | |------------------------------|--------------| | 单点修改+区间求 | 树状数组 | | 动态前缀 | 树状数组 | | 区间最值/区间覆盖 | 线段树 | | 区间修改(加/乘) | 线段树 | | 需自定义合并逻辑的统计问题 | 线段树 | > 树状数组在**简单区间求**场景中具有显著优势,而线段树是**复杂区间操作**的终极解决方案[^1][^2]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BiuPsYao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值