404、区域和检索-数组可修改
给你一个数组 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]
思路:
看到这道题,一想数组不就可以满足这个条件吗?于是简单的写了一下答案。
class NumArray:
def __init__(self, nums: List[int]):
self.nums = nums
def update(self, index: int, val: int) -> None:
self.nums[index] = val
def sumRange(self, left: int, right: int) -> int:
return sum(self.nums[left: right+1])
如果这样能够,那不就啪啪啪打力扣的脸吗?于是乎,当我按下提交按钮的那一刻,leetcode着实啪啪啪的打了我的脸,超出时间限制。
这段代码写的没毛病啊,那到底什么地方超时了呢?初始化和update应该不会有问题,那么出问题的地方就是在求和,怎样才能够缩小求和的数据量大小了,这个时候脑袋灵光一闪,分组呀,可以先缓存分组的和,然后根据再求范围内分组的和不就行了吗?
那么怎样分组呢?分组的长度为多少合适呢?数组长度的一半,好像没什么太大作用,那就数组长度的开方吧。
from math import sqrt
class NumArray:
def __init__(self, nums: List[int]):
n = len(nums)
size = int(sqrt(n))
self.nums = nums
self.sums = []
# 根据分组大小求出每个分组的和
for i in range(0, n, int(size)):
self.sums.append(sum(self.nums[i: i + size]))
self.size = size
def update(self, index: int, val: int) -> None:
# 修改数组元素值时,也需要同步修改元素所在分组的和的值 +修改值-原始值
self.sums[index // self.size] += val - self.nums[index]
self.nums[index] = val
def sumRange(self, left: int, right: int) -> int:
size = self.size
# 根据left和right所在分组进行求和
# 如果在同一个分组,那么直接返回分组内求和即可
# 如果不在同一个分组,需要对left所在分组的右侧求和 + right所在分组的左侧求和 + 左右分组中间的分组求和
l, r = left // size, right // size
if l == r:
return sum(self.nums[left: right + 1])
return sum(self.nums[left: (l + 1) * size]) + sum(self.nums[r*size: right + 1]) + sum(self.sums[l+1:r])