题目
题目来源:力扣(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)*/
