返回
用LeetCode 0303题实现区域和查询——数组不变性下的突破
前端
2024-02-07 07:24:35
**前言**
LeetCode 0303题“区域和检索 - 数组不可变”是一道经典的算法题,也是程序员面试的常见题目。这道题要求我们在数组不可变的情况下,高效地查询数组中某一段范围内的元素和。
**前缀和**
前缀和是一种简单而有效的解决办法。它通过预先计算数组中每个元素的前缀和,使得查询某一段范围内的元素和只需要计算相应前缀和之间的差值。
**差分**
差分是一种与前缀和类似的方法,但它存储的是相邻元素之间的差值。通过这种方式,查询某一段范围内的元素和只需要计算相应差值的和。
**树状数组**
树状数组是一种二进制索引树,它可以高效地查询和更新数组中的元素。在树状数组中,每个元素存储的是其自身的值以及其子孙节点的和。通过这种方式,查询某一段范围内的元素和只需要计算相应节点的和。
**比较**
这三种方法各有优缺点。前缀和的实现简单,查询时间复杂度为O(1),但更新时间复杂度为O(n)。差分的实现也比较简单,查询时间复杂度为O(1),更新时间复杂度为O(1)。树状数组的实现相对复杂,查询时间复杂度为O(log n),更新时间复杂度为O(log n)。
**代码示例**
```python
# 前缀和
def prefix_sum(nums):
n = len(nums)
pre_sum = [0] * (n + 1)
for i in range(1, n + 1):
pre_sum[i] = pre_sum[i - 1] + nums[i - 1]
return pre_sum
def range_sum(pre_sum, i, j):
return pre_sum[j + 1] - pre_sum[i]
# 差分
def difference(nums):
n = len(nums)
diff = [0] * n
for i in range(1, n):
diff[i] = nums[i] - nums[i - 1]
return diff
def range_sum(diff, i, j):
return diff[j] - diff[i - 1] + nums[i - 1]
# 树状数组
class BinaryIndexedTree:
def __init__(self, nums):
n = len(nums)
self.tree = [0] * (n + 1)
for i in range(1, n + 1):
self.update(i, nums[i - 1])
def update(self, i, val):
while i <= len(self.tree):
self.tree[i] += val
i += i & -i
def query(self, i):
sum = 0
while i > 0:
sum += self.tree[i]
i -= i & -i
return sum
def range_sum(tree, i, j):
return tree.query(j + 1) - tree.query(i)
# 时间复杂度对比
def time_complexity(n):
print("Prefix sum:")
print(" Query: O(1)")
print(" Update: O(n)")
print("Difference:")
print(" Query: O(1)")
print(" Update: O(1)")
print("Binary indexed tree:")
print(" Query: O(log n)")
print(" Update: O(log n)")
总结
LeetCode 0303题“区域和检索 - 数组不可变”是一道经典的算法题,它要求我们在数组不可变的情况下,高效地查询数组中某一段范围内的元素和。文章介绍了三种常见的解法:前缀和、差分以及树状数组,并对每种方法的原理、实现和复杂度进行了详细的分析。同时,文章还给出了这三种方法的代码示例和时间复杂度对比,以帮助读者更好地理解和选择合适的方法。