一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第8天,点击查看活动详情。
每日刷题 2021.04.08
- leetcode原题链接:leetcode-cn.com/problems/ra…
- 难度:中等
- 方法:树状数组
题目
- 给你一个数组 nums ,请你完成两类查询。
- 其中一类查询要求 更新 数组 nums 下标对应的值,另一类查询要求返回数组 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])
示例
输入:
["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] <= 1000 <= index < nums.length-100 <= val <= 1000 <= left <= right < nums.length- 调用
update和sumRange方法次数不大于3 * 10^4
解题思路
注意
- 想要在类中自定义方法,需要这样写
NumArray.prototype.lowbit,直接将其添加到原型对象上,才能使用this调用。
思路
lowbit函数:lowbit操作用于得到该数二进制分解的最小的2的次幂(即二进制数的最后一个1)- 例如
lowbit(2) = 2,2(0010)二进制分解的最小的2的次幂是2的1次方(0010)lowbit(5) = 1,5(1001)二进制分解的最小的2的次幂是1的一次方(0001)lowbit函数的实现:显而易见,一个数按位取反+1再并上本身就可以实现lowbit函数,恰好有符号数中负数的表示(补码)就是该数按位取反+1.
- 暴力解法就是, 维护一个前缀和数组, 当更新某个的元素的值时,计算出变化量,给需要更新的前缀和元素进行更新。
- 看代码题解的前提是知道什么是线段树,本题目解答就不放入图片了,就是树的每个节点包含了
start,end数组的区间,以及区间和sum。还有left左节点,right右节点。- 首先定义一个
TreeNode类,代码中定义的首字母小写了不过不影响 - 然后分别定义
NumArray类的方法,分别为生成线段树,也就是this.root = this.buildTree(nums,0,nums.length-1) - 定义
update更新方法, 定义sum求和方法
- 首先定义一个
AC代码
var NumArray = function(nums) {
this.nums = nums;
this.len = nums.length;
this.tree = new Array(this.len + 1).fill(0);
for(let i = 1; i <= this.len; i++) {
this.update(i - 1, this.nums[i - 1]);
}
};
NumArray.prototype.lowbit = function (x) {
return x & (-x);
}
NumArray.prototype.getSum = function (right) {
let res = 0;
while (right > 0) {
res += this.tree[right];
right -= this.lowbit(right);
}
return res;
}
/**
* @param {number} index
* @param {number} val
* @return {void}
*/
NumArray.prototype.update = function(index, val) {
// 原有的
index++;
let cur = this.getSum(index) - this.getSum(index - 1);
let k = val - cur;
while(index <= this.len) {
this.tree[index] += k;
index += this.lowbit(index)
}
};
/**
* @param {number} left
* @param {number} right
* @return {number}
*/
NumArray.prototype.sumRange = function(left, right) {
return this.getSum(right + 1) - this.getSum(left)
};
总结
- 初次学习树状数组,有参考一些大佬的题解和视频,帮助很大