- 本人的LeetCode账号:魔术师的徒弟,欢迎关注获取每日一题题解,快来一起刷题呀~
- 本人Gitee账号:路由器,欢迎关注获取博客内容源码。
树状数组和其他的高级数据结构不同,它非常的好写,同时解决问题也比较局限,所以树状数组的题目的难度主要集中在思考而非代码。
一、基本原理
树状数组可以解决两个操作:快速的求前缀和、修改某一个数,这两个操作都是O(logn)的。
这两个操作如果我们直接来操作:
- 存原数组,前缀和O(N),修改一个数O(1)
- 维护前缀和,前缀和O(1),修改一个数O(N)
有一种鱼和熊掌不可兼得的感觉,但是我们的题目中时间复杂度一般取决于最糟糕的时间复杂度,所以如果有n次查询,那么复杂度会达到O(n^2)。树状数组有一个折中的思想,它让这两个操作的时间复杂度都变成了O(logn),这样总时间复杂度就是O(nlogn),就会快很多了。
它是一种基于二进制的方法来解决这个问题的。
假设我们有一个数x,其二进制表示为:
x = 2 i k + 2 i k − 1 + . . . + 2 i 1 i k > = i k − 1 > = . . . > = i 1 x = 2^{i_k} + 2^{i_{k - 1}} + ...+2^{i_{1}}\\ i_{k}>=i_{k-1}>=...>=i_1 x=2ik+2ik−1+...+2i1ik>=ik−1>=...>=i1
假设我们想求的是下标为1~x的总和,那么我们可以把1~x这个区间划分成k部分:
( x − 2 i 1 , x ] ( x − 2 i 1 − 2 i 2 , x − 2 i 1 ] . . . ( 0 , x − 2 i 1 − 2 i 2 − . . . − 2 i k − 1 ] (x-2^{i_1},x]\\(x-2^{i_1}-2^{i_2}, x-2^{i_1}]\\...\\(0,x-2^{i_1}-2^{i_2}-...-2^{i_{k-1}}] (x−2i1,x](x−2i1−2i2,x−2i1]...(0,x−2i1−2i2−...−2ik−1]
这样就把下标为1~x这个区间划分成了logx份,这样如果算1~x的总和,只需要求logx个区间的和就能算出来了。
这个思想就是让我们在logn的时间复杂度中使用前缀和的思想。
下面来看看区间中元素的个数和区间右端点有什么关系:
( x − 2 i 1 , x ] , 元 素 个 数 2 1 i 个 ( x − 2 i 1 − 2 i 2 , x − 2 i 1 ] , 元 素 个 数 2 2 i 个 . . . ( 0 , x − 2 i 1 − 2 i 2 − . . . − 2 i k − 1 ] , 元 素 个 数 2 k i 个 (x-2^{i_1},x], 元素个数2^i_1个\\ (x-2^{i_1}-2^{i_2}, x-2^{i_1}],元素个数2^i_2个\\ ...\\ (0,x-2^{i_1}-2^{i_2}-...-2^{i_{k-1}}],元素个数2^i_k个 (x−2i1,x],元素个数21i个(x−2i1−2i2,

本文介绍了树状数组的基本原理,包括其在快速求前缀和、修改元素值方面的优势,以及在实际问题如楼兰图腾、区间和检索等中的应用实例。通过理解区间元素个数的计算和父节点查找,掌握如何使用树状数组优化nlogn复杂度问题。
最低0.47元/天 解锁文章

被折叠的 条评论
为什么被折叠?



