我的LeetCode代码仓:https://github.com/617076674/LeetCode
原题链接:https://leetcode-cn.com/problems/range-sum-query-mutable/description/
题目描述:
知识点:线段树
思路:线段树
本题是LeetCode303——区域和检索的加强版,由于新增了update()操作,LeetCode303——区域和检索中的思路一时间复杂度太高,不合适,我们选择对线段树添加更新操作。
构造函数和sumRange()函数的时间复杂度与LeetCode303——区域和检索中分析的相同。
update()函数的时间复杂度是O(logn),其中n为数组的长度。
空间复杂度是O(n)。
JAVA代码:
public class NumArray {
private class SegmentTree {
private Integer[] tree;
private Integer[] data;
public SegmentTree(Integer[] arr) {
data = new Integer[arr.length];
for (int i = 0; i < arr.length; i++) {
data[i] = arr[i];
}
tree = new Integer[4 * arr.length];
buildSegmentTree(0, 0, data.length - 1);
}
/*
* 在treeIndex的位置创建表示区间[left, right]的线段树
*/
private void buildSegmentTree(int treeIndex, int left, int right) {
if (left == right) {
tree[treeIndex] = data[left];
return;
}
int leftTreeIndex = leftChild(treeIndex);
int rightTreeIndex = rightChild(treeIndex);
int mid = left + (right - left) / 2; //为了防止数据越界!!!
buildSegmentTree(leftTreeIndex, left, mid);
buildSegmentTree(rightTreeIndex, mid + 1, right);
tree[treeIndex] = tree[leftTreeIndex] + tree[rightTreeIndex];
}
/*
* 返回满二叉树的数组表示中,一个索引所表示的元素的左孩子节点的索引
*/
private int leftChild(int index) {
return 2 * index + 1;
}
/*
* 返回满二叉树的数组表示中,一个索引所表示的元素的左孩子节点的索引
*/
private int rightChild(int index) {
return 2 * index + 2;
}
/*
* 在线段树中所涉及的操作不需要通过一个节点去寻找它的父亲节点,因此不需要parent()这个函数
*/
/*
* 返回区间[queryL, queryR]的值
*/
public Integer query(int queryL, int queryR) {
return query(0, 0, data.length - 1, queryL, queryR);
}
/*
* 在以treeID为根的线段树中[left...right]的范围里,搜索区间[queryL...queryR]的值
*/
private Integer query(int treeIndex, int left, int right, int queryL, int queryR) {
if (left == queryL && right == queryR) {
return tree[treeIndex];
}
int mid = left + (right - left) / 2;
int leftTreeIndex = leftChild(treeIndex);
int rightTreeIndex = rightChild(treeIndex);
if (queryL >= mid + 1) {
return query(rightTreeIndex, mid + 1, right, queryL, queryR);
} else if (queryR <= mid) {
return query(leftTreeIndex, left, mid, queryL, queryR);
} else {
Integer leftResult = query(leftTreeIndex, left, mid, queryL, mid);
Integer rightResult = query(rightTreeIndex, mid + 1, right, mid + 1, queryR);
return leftResult + rightResult;
}
}
//将index位置的值,更新为e
public void update(int i, Integer val){
data[i] = val;
update(0, 0, data.length - 1, i, val);
}
//在以treeIndex为根的线段树中更新index的值为e
private void update(int treeIndex, int left, int right, int index, Integer e){
if(left == right){
tree[treeIndex] = e;
return;
}
int mid = (right - left) / 2 + left;
int leftTreeIndex = leftChild(treeIndex);
int rightTreeIndex = rightChild(treeIndex);
if(index >= mid + 1){
update(rightTreeIndex, mid + 1, right, index, e);
}else{
update(leftTreeIndex, left, mid, index, e);
}
tree[treeIndex] = tree[leftTreeIndex] + tree[rightTreeIndex];
}
}
private SegmentTree segmentTree;
public NumArray(int[] nums) {
if (nums.length > 0) {
Integer[] data = new Integer[nums.length]; //int[]是不能自动包装转换为Integer[]的!!!
for (int i = 0; i < nums.length; i++) {
data[i] = nums[i];
}
segmentTree = new SegmentTree(data);
}
}
public void update(int i, int val) {
segmentTree.update(i, val);
}
public int sumRange(int i, int j) {
return segmentTree.query(i, j);
}
}
LeetCode解题报告: