307. 区域和检索-数组可修改

题目描述:

给你一个数组 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])

测试用例:

示例 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
  • 调用 update 和 sumRange 方法次数不大于 3 * 10^4

解题分析及思路:

本题可以采用树状数组 🔗进行解答,可以为nums构造一棵二叉索引树tree。

l := len(nums)
tree := make([]int, l+1)
for i := 1; i <= l; i++ {
    index := i
    for index <= l {
        tree[index] += nums[i-1]
        index += lowBit(index)
    }
}

当然离不开两个函数

func lowBit(index int) int {
	return index & -index
}

func sum(index int, a []int) (ans int) {
	for index > 0 {
		ans += a[index]
		index -= lowBit(index)
	}
	return
}

为了保证每次更新能够直到原数组中下标为index的值,除了保存二叉索引树之外,还需要将nums保存下来。

在执行Update函数时,为了后续的求和操作,除了需要更新愿数组时,还需要将tree进行更新。

func (this *NumArray) Update(index int, val int) {
	subVal := val - this.nums[index]
	this.nums[index] = val
	index++
	for index < len(this.tree) {
		this.tree[index] += subVal
		index += lowBit(index)
	}
}

SumRange函数调用sum方法即可。

func (this *NumArray) SumRange(left int, right int) int {
	return sum(right+1, this.tree) - sum(left, this.tree)
}

复杂度:

  • 构造函数:O(nlogn),其中 nn 是数组 nums 的大小。add 函数的时间复杂度是 O(logn),总共调用 nn 次。
  • update 函数:O(logn)。add 函数的时间复杂度是 O(logn)。
  • sumRange 函数:O(logn)。prefixSum 函数的时间复杂度是 O(logn)。

执行结果:

  • 执行用时: 460 ms, 在所有 Go 提交中击败了84.96%的用户
  • 内存消耗:22.8 MB, 在所有 Go 提交中击败了32.93%的用户
Tags :

通过次数 93.7K 提交次数 174.5K 通过率 53.7%

Related Posts

1026. 节点与其祖先之间的最大差值

## 题目描述:给定二叉树的根节点 root,找出存在于 不同 节点 A 和 B 之间的最大值 V,其中 V = |A.val - B.val|,且 A 是 B 的祖先。(如果 A 的任何子节点之一为 B,或者 A 的任何子节点是 B 的祖先,那么我们认为 A 是 B 的祖先)示例 1: ![](/img/leetcode/1026节点与其祖先之间的最大差值/tmp-tre

read more

1038. 从二叉搜索树到更大和树

## 题目描述:给定一个二叉搜索树 root (BST),请将它的每个节点的值替换成树中大于或者等于该节点值的所有节点值之和。提醒一下, 二叉搜索树 满足下列约束条件:- 节点的左子树仅包含键 小于 节点键的节点。 - 节点的右子树仅包含键 大于 节点键的节点。 - 左右子树也必须是二叉搜索树。*示例 1:***![](/img/leetcode/

read more

105. 从前序与中序遍历序列构造二叉树

## 题目描述:给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。示例 1: ``` 输入: preorder = [3,9,20,15,7], inorder = [

read more

106. 从中序与后序遍历序列构造二叉树

## 题目描述:给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。示例 1: ``` 输入:inorder = [9,3,15,20,7], postorder

read more

109. 有序链表转换二叉搜索树

## 题目描述:给定一个单链表的头节点 head ,其中的元素 按升序排序 ,将其转换为高度平衡的二叉搜索树。本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差不超过 1。示例 1: ``` 输入: head = [-10,-3,0,5,9] 输出: [0,-3,9

read more

114. 二叉树展开为链表

## 题目描述:给你二叉树的根结点 root ,请你将它展开为一个单链表:- 展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null 。 - 展开后的单链表应该与二叉树 先序遍历 顺序相同。示例 1: ``` 输入:root

read more