以上是 Leetcode 中与线段树有关的题目
线段树解决的是求 区间问题 ,且该 区间 会被修改
线段树的特点:每个节点代表一个区间
Leetcode 307 区域和检索 - 数组可修改(区间大小固定)
使用数组模拟树 ,因为 nums 数组的大小是固定的,而树的容量大小固定为4倍的数组大小
当前节点在数组中的位置 curPos,左子树节点位置 curPos*2+1,右子树节点位置 curPos*2+2
当前节点表示的区间 [ curLeft , curRight ] ,区间中间点 mid = curLeft + ( curRight - curLeft ) / 2 ,则当前节点的左子树的区间为 [ curLeft , mid ] ,右子树的区间为 [ mid + 1 , curRight ]
线段树的两种操作:
1. 更新操作:(每个节点代表一个区间)代入当前节点 根节点 curPos = 0,当前节点表示的区间 [ curLeft , curRight ] ;
向下寻找到需要更新的目标节点,目标节点表示的区间为 [ index , index ]
如果当前节点的区间 curLeft = curRight ,表示找到目标节点区间,更新目标节点
如果目标区间 index 小于等于当前节点左子树,往左子树上继续寻找;否则,往右子树上继续寻找
更新后,向上回溯,更新当前节点
2. 区间检索:(每个节点代表一个区间)代入当前节点 根节点 curPos = 0,当前节点表示的区间 [ curLeft , curRight ] ;
向下寻找到所求的目标区间,目标区间为 [ left , right ]
如果目标区间与当前节点所代表的区间一致,返回当前节点保存的结果;
如果目标区间 right 小于等于当前节点左子树,往左子树上继续寻找;
如果目标区间 left 大于当前节点右子树,往右子树上继续寻找;
如果目标区间在包含在两个子树之间,求往左子树和右子树上继续寻找的和
class NumArray2 {
int[] tree;
int len;
// 初始化 构造线段树
public NumArray2(int[] nums) {
len = nums.length;
tree = new int[len * 4];
buildTree(0, 0, len - 1, nums);
}
public void update(int index, int val) {
change(index, val, 0, 0, len - 1);
}
public int sumRange(int left, int right) {
return sum(left, right, 0, 0, len - 1);
}
public int sum(int left, int right, int curPos, int curLeft, int curRight) {
if (left == curLeft && right == curRight) {
return tree[curPos];
}
int mid = curLeft + (curRight - curLeft) / 2;
if (right <= mid) {
return sum(left, right, curPos * 2 + 1, curLeft, mid);
} else if (left > mid) {
return sum(left, right, curPos * 2 + 2, mid + 1, curRight);
} else {
return sum(left, mid, curPos * 2 + 1, curLeft, mid) + sum(mid + 1, right, curPos * 2 + 2, mid + 1, curRight);
}
}
// 更新节点
public void change(int index, int val, int curPos, int curLeft, int curRight) {
if (curLeft == curRight) {
tree[curPos] = val;
return;
}
int mid = curLeft + (curRight - curLeft) / 2;
if (index <= mid) {
change(index, val, curPos * 2 + 1, curLeft, mid);
} else {
change(index, val, curPos * 2 + 2, mid + 1, curRight);
}
tree[curPos] = tree[curPos * 2 + 1] + tree[curPos * 2 + 2];
}
public void buildTree(int curPos, int left, int right, int[] nums) {
if (left == right) {
tree[curPos] = nums[left];
return;
}
int mid = left + (right - left) / 2;
buildTree(curPos * 2 + 1, left, mid, nums);
buildTree(curPos * 2 + 2, mid + 1, right, nums);
// 后续遍历, 当前节点为左右子树的和
tree[curPos] = tree[curPos * 2 + 1] + tree[curPos * 2 + 2];
}
}
参考来源:线段树详解