树状数组详解

本文深入探讨了树状数组(也称 Fenwick Tree)在数组修改与区间查询中的应用,它能将操作复杂度降低到O(logn)。Lowbit函数用于获取二进制表示中最低位的1,是树状数组实现的关键。通过实例解析了如何使用树状数组进行单点更新和区间求和,并提供了LeetCode 307题的解题模板,展示了树状数组在实际问题中的运用。
摘要由CSDN通过智能技术生成


原理

用来解决数组修改与区间查询复杂度过高
对数组来说,暴力修改与查询的复杂度分别为O(1),O(n),总体复杂度为O(qn);若使用前缀和优化查询复杂度会变为O(1),修改的复杂度会变为O(n),总体复杂度仍为O(qn)
树状数组的修改与查询复杂度为O(logn),有效避免超时

详解

lowbit()函数

该函数的作用为: 求二进制数中最低位的1表示的十进制数
计算机中数值用补码进行存储,假设一数值为X,则-X可以通过
对X按位取反后 + 1 得到

let lowbit = functionX{
	return X & -X;
}

将X与-X按位与,便可得到二进制中最低位的1。

树状数组


在A[]数组的基础上建立C[]数组,关系如下

C[8]=A[1]+A[2]+A[3]+A[4]+A[5]+A[6]+A[7]+A[8]
C[7]=A[7]
C[6]=A[5]+A[6]
C[5]=A[5]
C[4]=A[1]+A[2]+A[3]+A[4]
C[3]=A[3]
C[2]=A[1]+A[2]
C[1]=A[1]

C[n]为后缀和,其长度与n所在的层数(自底向上数)相关

更新树状数组 可使用x += lowBit(x)来更新C[n]数组

查询区间和 可使用x -= lowBit(x) 查找小于x所在的区间

查询[left,right]区间,可先求出[1,right]区间和,与[1,left]区间和,相减即可

模板题

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

//单点更新,区间求和
var NumArray = function(nums) {
    this.tree = new Array(nums.length + 1).fill(0);
    this.nums = nums;
    for (let i = 0; i < nums.length; i++) {
        this.add(i + 1, nums[i]);
        //构建C[N]
    }
};

NumArray.prototype.update = function(index, val) {
    this.add(index + 1, val - this.nums[index]);
    this.nums[index] = val;
};

NumArray.prototype.sumRange = function(left, right) {
    return this.prefixSum(right + 1) - this.prefixSum(left);
};

NumArray.prototype.lowBit = function(x) {
    return x & -x;
}

NumArray.prototype.add = function(index, val) {
    while (index < this.tree.length) {
        this.tree[index] += val;
        index += this.lowBit(index);
    }
}

NumArray.prototype.prefixSum = function(index) {
    let sum = 0;
    while (index > 0) {
        sum += this.tree[index];
        index -= this.lowBit(index);
    }
    return sum;
}

…待续
2. 区间更新,单点查询
3. 区间更新,区间查询

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值