区域和检索 - 数组可修改

93 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天,点击查看活动详情

307. 区域和检索 - 数组可修改 - 力扣(LeetCode)

给你一个数组 nums ,请你完成两类查询。

  1. 其中一类查询要求 更新 数组 nums 下标对应的值
  2. 另一类查询要求返回数组 nums 中索引 left 和索引 right 之间( 包含 )的nums元素的  ,其中 left <= right

实现 NumArray 类:

  • NumArray(int[] nums) 用整数数组 nums 初始化对象
  • void update(int index, int val)nums[index] 的值 更新val
  • int sumRange(int left, int right) 返回数组 nums 中索引 left 和索引 right 之间( 包含 )的nums元素的  (即,nums[left] + nums[left + 1], ..., nums[right]

示例 1:

输入
["NumArray", "sumRange", "update", "sumRange"]
[[[1, 3, 5]], [0, 2], [1, 2], [0, 2]]
输出
[null, 9, null, 8]
解释
NumArray numArray = new NumArray([1, 3, 5]);
numArray.sumRange(0, 2); // 返回 1 + 3 + 5 = 9
numArray.update(1, 2); // nums = [1,2,5]
numArray.sumRange(0, 2); // 返回 1 + 2 + 5 = 8

提示:

  • 1 <= nums.length <= 3 * 10^4
  • -100 <= nums[i] <= 100
  • 0 <= index < nums.length
  • -100 <= val <= 100
  • 0 <= left <= right < nums.length
  • 调用 updatesumRange 方法次数不大于 3 * 10^4

解题

/**
 * @param {number[]} nums
 */
var NumArray = function (nums) {
  const tree = [];
  const n = nums.length;
  const buildTree = (left, right, idx) => {
    if (left === right) {
      tree[idx] = nums[left];
    } else {
      const mid = (left + right) >> 1;
      const leftVal = buildTree(left, mid, (idx << 1) + 1);
      const rightVal = buildTree(mid + 1, right, (idx << 1) + 2);
      tree[idx] = leftVal + rightVal;
    }
    return tree[idx];
  };
  buildTree(0, n - 1, 0);
  this.tree = tree;
  this.nums = nums;
  this.length = n;
};

/**
 * @param {number} index
 * @param {number} val
 * @return {void}
 */
NumArray.prototype.update = function (index, val) {
  let left = 0;
  let right = this.length - 1;
  let idx = 0;
  const diff = val - this.nums[index];
  this.nums[index] = val;
  this.tree[idx] += diff;
  while (left != right) {
    let mid = (left + right) >> 1;
    if (mid >= index) {
      right = mid;
      idx = (idx << 1) + 1;
    } else {
      left = mid + 1;
      idx = (idx << 1) + 2;
    }
    this.tree[idx] += diff;
  }
};

/**
 * @param {number} left
 * @param {number} right
 * @return {number}
 */
NumArray.prototype.sumRange = function (left, right) {
  const fn = (l, r, idx) => {
    if (l >= left && r <= right) {
      return this.tree[idx];
    } else if (l > right || r < left) {
      return 0;
    }
    const mid = (l + r) >> 1;
    return fn(l, mid, (idx << 1) + 1) + fn(mid + 1, r, (idx << 1) + 2);
  };
  return fn(0, this.length - 1, 0);
};

/**
 * Your NumArray object will be instantiated and called as such:
 * var obj = new NumArray(nums)
 * obj.update(index,val)
 * var param_2 = obj.sumRange(left,right)
 */