前言
线段树其实属于比较高级的数据结构了,本人并不是竞赛选手,这里的代码也是借鉴的 bobo 老师的视频课来实现的,面试什么的一般是不会考的,这里主要是出于兴趣练练手
问题引入
给定一个整数数组 nums,求出数组从索引 i 到 j (i ≤ j) 范围内元素的总和,包含 i, j 两点。
update(i, val) 函数可以通过将下标为 i 的数值更新为 val,从而对数列进行修改。
示例:
Given nums = [1, 3, 5] |
说明:
- 数组仅可以在 update 函数下进行修改。
- 你可以假设 update 函数与 sumRange 函数的调用次数是均匀分布的。
这题如果数组不能修改的话就好说了,可以直接利用数组的前缀和,但是这里数组是会变化的,难道没更新一次都要重新遍历么?那也太慢了吧,有没有一种结构能高效的插入同时也能高效的查询?
线段树
线段树,它在各个节点保存一条线段(数组中的一段子数组),主要用于高效解决连续区间的动态查询问题,由于二叉结构的特性(它是一颗平衡二叉树),它基本能保持每个操作的复杂度为O(logN)
线段树的每个节点表示一个区间,父区间为[a,b]
则左子区间为[a,(a+b)/2]
右子区间为[(a+b)/2+1,b]
最底层的叶子节点就是对应的一个个具体的元素值,这里我们采用数组来实现线段树
import java.util.function.*; |
没啥好说的,整体还是挺简单的,代码中用到了 Java8 的函数式接口,确实挺方便的
其实我觉得有一个比较关键的点就是线段树需要多大的数组空间?
首先一颗 H 层(H 从 1 开始)的满二叉树一共有 2^H-1
个节点,我们忽略那一个节点,约为2^H
个节点,而最后一层(h-1 层)有 2^(h-1)
个节点,也就是说最后一层的节点树大致等于前面所有层节点的和,所以我们可以得出一个结论,在线段树中如果需要表示的区间大小为 n,并且 n 刚好等于 2 的 k 次幂的话(也就是放好构成一颗满二叉树),那么就只需要 2n 的节点个数,但是如果是n=2^k+c
那么当前层就存不下这 n 个元素,需要存到下一层,也就是空间还需要* 2,所以最后我们就需要 4n 的空间去存储这颗线段树。
这个时候再回头去做上面的题就会很简单了😁
线段树其实还有很多的扩展,上面的是最最最基本的最简单的线段树结构,我还根本就没摸到线段树的门😂,只是知道了有这么个结构
由于我实在是太菜了,也没有时间去了解那些结构了
当然面试的时候并不会考线段树这些玩意儿,我也只是为了练练手,真正的竞赛的题目也不会像上面那么简单,了解即可😅