区域和检索 树状数组C++

本文详细介绍了如何使用树状数组解决LeetCode 307题中的区域和检索问题,涉及数组修改后的更新策略和范围求和的高效查询。通过实例演示了如何在C++中实现NumArray类,包括update方法和sumRange方法的操作过程。
摘要由CSDN通过智能技术生成

区域和检索 树状数组

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

假设有一个长度为9的数组,数组中的值arr[i],前i个的总和sum[i]如下。

在这里插入图片描述

某次,arr[3]修改为0,那么有6个数据需要更新,查询前5个的总和为sum[4] = 11

在这里插入图片描述

某次,arr[0]修改为3,那么有9个数据需要更新,查询前5个的总和为sum[4] = 13

在这里插入图片描述

有n个数,第i个修改了,那么sum(i)到sum(n-1)需要更新,n为数组长度

树状数组

lowbit (x)= x & (-x)取x在二进制中的最后一位1。

树状数组用C[i]表示,值都初始化为0,下标从1开始。

在这里插入图片描述

arr[3] = 4修改为0后,相当于减取4,管理到它的节点为树状数组中的C[4],管理到C[4]的下标为4 & (-4) = 8,为C[8]。管理到C[8]的下标为8 & (-8) = 16,超过长度,退出。只有C[4] ,C[8]需要减去4。

在这里插入图片描述

查询前5个数的总和为,首先是C[5]。5 - 5 & (-5) = 4,然后是C[4]。4 - 4 &(-4) = 0。因此只有C[5]和C[4],C[5]+C[4]=11。

在这里插入图片描述

arr[0] = 1修改为3,相当于加2,管理到它的节点为树状数组中的C[1],管理到C[1]的下标为 1 + 1 & (-1) = 2,为C[2]。管理到C[2]的下标为2 + 2 & (-2) = 4,为C[4]。管理到C[4]的下标为4 + 4&(-4) = 8,为C[8]。管理到C[8]的下标为8 + 8 & (-8) = 16,超过长度,退出。因此,只有C[1]、C[2]、C[4]、C[8],需要加2。

在这里插入图片描述

查询前5个的总和,查询前7个数的和,只需要查询C[7]、C[6]、C[4]=26。只需要加3个。

在这里插入图片描述

给你一个数组 nums ,请你完成两类查询,其中一类查询要求更新数组下标对应的值,另一类查询要求返回数组中某个范围内元素的总和。
实现 NumArray 类:
NumArray(int[] nums) 用整数数组 nums 初始化对象
void update(int index, int val) 将 nums[index] 的值更新为 val
int sumRange(int left, int right) 返回子数组 nums[left, right] 的总和(即,nums[left] + nums[left + 1], …, nums[right])
示例:
输入:
[“NumArray”, “sumRange”, “update”, “sumRange”]
[[[1, 3, 5]], [0, 2], [1, 2], [0, 2]]
输出:
[null, 9, null, 8]
解释:
NumArray numArray = new NumArray([1, 3, 5]);
numArray.sumRange(0, 2); // 返回 9 ,sum([1,3,5]) = 9
numArray.update(1, 2); // nums = [1,2,5]
numArray.sumRange(0, 2); // 返回 8 ,sum([1,2,5]) = 8

#define lowbit(num) ((num)&(-num))

class NumArray {
private:
    vector<int>tree;
    vector<int>nums;
    int size = 0;

    void add(int index, int val) {
        while (index <= size) {
            tree[index] += val;
            index += lowbit(index);
        }
    }

    int query(int index) {
        int sum = 0;
        while (index > 0) {
            sum += tree[index];
            index -= lowbit(index);
        }
        return sum;
    }
public:

    NumArray(vector<int>& nums) {
        this->size = nums.size();
        this->nums = nums;
        tree.resize(size + 1, 0);
        for (int i = 0; i < size; i++) {
            add(i + 1, nums[i]);
        }
    }

    void update(int index, int val) {
        int delta = val - nums[index];
        nums[index] = val;
        add(index + 1, delta);
    }

    int sumRange(int left, int right) {
        return query(right + 1) - query(left);
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值