题目
题目来源:力扣(LeetCode)
给定一个整数数组 nums,求出数组从索引 i 到 j(i ≤ j)范围内元素的总和,包含 i、j 两点。
实现 NumArray 类:
NumArray(int[] nums) 使用数组 nums 初始化对象
int sumRange(int i, int j) 返回数组 nums 从索引 i 到 j(i ≤ j)范围内元素的总和,包含 i、j 两点(也就是 sum(nums[i], nums[i + 1], … , nums[j]))
示例:
输入:
[“NumArray”, “sumRange”, “sumRange”, “sumRange”]
[[[-2, 0, 3, -5, 2, -1]], [0, 2], [2, 5], [0, 5]]
输出:
[null, 1, -1, -3]
解释:
NumArray numArray = new NumArray([-2, 0, 3, -5, 2, -1]);
numArray.sumRange(0, 2); // return 1 ((-2) + 0 + 3)
numArray.sumRange(2, 5); // return -1 (3 + (-5) + 2 + (-1))
numArray.sumRange(0, 5); // return -3 ((-2) + 0 + 3 + (-5) + 2 + (-1))
思路分析
解法:树状数组
- 根据输⼊数组进⾏初始化,这⾥通过计算前缀和初始化
- 在查找数组中某个范围内元素的总和时,分为三种情况:
- 情况⼀:若mid刚好在sLeft的左侧
- 情况⼆:若mid刚好在sLeft的右侧
- 情况三:若mid刚好在 sLeft和sRight中间 然后分别对于三种情况进⾏递归查找
/**
* @param {number[]} nums
*/
var NumArray = function (nums) {
this.arrTree = Array(2 * nums.length);
this.numsArr = nums;
this.setTree(0, 0, this.numsArr.length - 1);
// console.log(this.arrTree)
};
NumArray.prototype.setTree = function (i, left, right) {//构建线段树
if (left > right) return 0;
if (left == right) {
this.arrTree[i] = this.numsArr[left];
return this.arrTree[i];
}
let mid = ((left + right) - (left + right) % 2) / 2;
// 构建i节点的左⼦线段树
let leftVal = this.setTree(2 * i + 1, left, mid);
//构建i节点的右⼦线段树
let rightVal = this.setTree(2 * i + 2, mid + 1, right);
this.arrTree[i] = leftVal + rightVal;
return this.arrTree[i];
}
/**
* @param {number} index
* @param {number} val
* @return {void}
*/
NumArray.prototype.update = function (index, val) {// 更新线段树中的值
this.diff = val - this.numsArr[index];
this.numsArr[index] = val;
this.index = index;
this.updateArrTree(0, 0, this.numsArr.length - 1);
// console.log(this.arrTree)
};
NumArray.prototype.updateArrTree = function (i, left, right) {
if (left > right) return;
if (left == right && left === this.index) {
this.arrTree[i] += this.diff;
return;
}
// this.arrTree[i] += this.diff;
this.arrTree[i] += this.diff;
let mid = ((left + right) - (left + right) % 2) / 2;
// 如果index⼩于等于mid顺着左⼦树查找,
if (this.index <= mid) {
this.updateArrTree(2 * i + 1, left, mid);
} else {// 否则顺着右⼦树查找
this.updateArrTree(2 * i + 2, mid + 1, right);
}
}
/**
* @param {number} left
* @param {number} right
* @return {number}
*/
NumArray.prototype.sumRange = function (left, right) {
return this.sumArrTree(0, 0, this.numsArr.length - 1, left, right);
};
NumArray.prototype.sumArrTree = function (i, left, right, sLeft, sRight) {
if (left > sRight || right < sLeft) {
return 0;
}
if (sLeft <= left && sRight >= right) {
// console.log('a,',this.arrTree[i])
return this.arrTree[i];
}
let mid = ((left + right) - (left + right) % 2) / 2;
if (sRight <= mid) {// 若mid刚好在sLeft的左侧
return this.sumArrTree(2 * i + 1, left, mid, sLeft, sRight);
} else if (sLeft > mid) {// 若mid刚好在sLeft的右侧
return this.sumArrTree(2 * i + 2, mid + 1, right, sLeft, sRight)
} else {// 若mid刚好在 sLeft和sRight中间
return this.sumArrTree(2 * i + 1, left, mid, sLeft, mid) +
this.sumArrTree(2 * i + 2, mid + 1, right, mid + 1, sRight);
}
}
/**
* Your NumArray object will be instantiated and called as such:
* var obj = new NumArray(nums)
* var param_1 = obj.sumRange(left,right)
*/