LeetCode 题解工作台
区域和检索 - 数组可修改
给你一个数组 nums ,请你完成两类查询。 其中一类查询要求 更新 数组 nums 下标对应的值 另一类查询要求返回数组 nums 中索引 left 和索引 right 之间( 包含 )的nums元素的 和 ,其中 left 实现 NumArray 类: NumArray(int[] nums) …
4
题型
6
代码语言
3
相关题
当前训练重点
中等 · 数组·结合·design
答案摘要
树状数组,也称作“二叉索引树”(Binary Indexed Tree)或 Fenwick 树。 它可以高效地实现如下两个操作: 1. 单点更新 $update(x, delta)$: 把序列 位置的数加上一个值 ;
Interview AiBoxInterview AiBox 实时 AI 助手,陪你讲清 数组·结合·design 题型思路
题目描述
给你一个数组 nums ,请你完成两类查询。
- 其中一类查询要求 更新 数组
nums下标对应的值 - 另一类查询要求返回数组
nums中索引left和索引right之间( 包含 )的nums元素的 和 ,其中left <= right
实现 NumArray 类:
NumArray(int[] nums)用整数数组nums初始化对象void update(int index, int val)将nums[index]的值 更新 为valint 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 * 104-100 <= nums[i] <= 1000 <= index < nums.length-100 <= val <= 1000 <= left <= right < nums.length- 调用
update和sumRange方法次数不大于3 * 104
解题思路
方法一:树状数组
树状数组,也称作“二叉索引树”(Binary Indexed Tree)或 Fenwick 树。 它可以高效地实现如下两个操作:
- 单点更新 : 把序列 位置的数加上一个值 ;
- 前缀和查询 :查询序列 区间的区间和,即位置 的前缀和。
这两个操作的时间复杂度均为 。
树状数组最基本的功能就是求比某点 小的点的个数(这里的比较是抽象的概念,可以是数的大小、坐标的大小、质量的大小等等)。
对于本题,我们在构造函数中,先创建一个树状数组,然后遍历数组中每个元素的下标 (从 开始)和对应的值 ,调用 ,即可完成树状数组的初始化。时间复杂度为 。
对于 ,我们可以通过 得到区间和。时间复杂度为 。
对于 ,我们可以先通过 得到原来的值 ,然后调用 ,即可完成更新。时间复杂度为 。
空间复杂度为 。
class BinaryIndexedTree:
__slots__ = ["n", "c"]
def __init__(self, n):
self.n = n
self.c = [0] * (n + 1)
def update(self, x: int, delta: int):
while x <= self.n:
self.c[x] += delta
x += x & -x
def query(self, x: int) -> int:
s = 0
while x > 0:
s += self.c[x]
x -= x & -x
return s
class NumArray:
__slots__ = ["tree"]
def __init__(self, nums: List[int]):
self.tree = BinaryIndexedTree(len(nums))
for i, v in enumerate(nums, 1):
self.tree.update(i, v)
def update(self, index: int, val: int) -> None:
prev = self.sumRange(index, index)
self.tree.update(index + 1, val - prev)
def sumRange(self, left: int, right: int) -> int:
return self.tree.query(right + 1) - self.tree.query(left)
# Your NumArray object will be instantiated and called as such:
# obj = NumArray(nums)
# obj.update(index,val)
# param_2 = obj.sumRange(left,right)
复杂度分析
| 指标 | 值 |
|---|---|
| 时间 | Depends on the final approach |
| 空间 | Depends on the final approach |
面试官常问的追问
外企场景- question_mark
Can the candidate suggest a more efficient solution than brute force?
- question_mark
Does the candidate understand the trade-offs between different data structures like BIT and Segment Tree?
- question_mark
How well does the candidate describe optimizing time complexity for both sum queries and updates?
常见陷阱
外企场景- error
Not recognizing that a brute force solution may be too slow for large inputs.
- error
Failing to implement efficient update handling in the chosen data structure.
- error
Incorrectly managing the data structure’s memory usage, especially with Segment Trees.
进阶变体
外企场景- arrow_right_alt
Implementing with a Binary Indexed Tree instead of a Segment Tree.
- arrow_right_alt
Supporting additional operations like range minimum query alongside sum queries.
- arrow_right_alt
Optimizing space complexity by adjusting the data structure size or approach.