题目
303. 区域和检索
难度:简单
题目分析: 一开始看到题目,感觉有点莫名其妙,不就是直接调用python内置的函数,就可以求解出来嘛。为什么要强调多次调用呢?而且,这跟动态规划有啥关系啊?
解法一就朴素的解法,时间竟然要1.2秒……于是我看了答案,对应解法二,只需要92毫秒……我才真正明白这道题的考点。
如果这个求和只是运行一次,那么解法一是最直接最好的方法,然而,如果需要反复使用,使用缓存可能是更好的方式。这里回到动态规划的核心思想:使用缓存,来提高问题的求解速度。 换句话说,一切可以使用空间换时间的算法,可能都可以归类为动态规划的求解范围。
解法一:
class NumArray:
def __init__(self, nums: List[int]):
self._nums = list(nums) # 断开二者联系
def sumRange(self, i: int, j: int) -> int:
return sum(self._nums[i:j+1])
运行结果:
分析:
如果反复调用求和函数,很多计算时反复进行的,从而拖慢了程序的速度。
解法二:
class NumArray:
def __init__(self, nums: List[int]):
## 定义 sum[]数组,k表示前k-1个数的和
self._nums =[0]*(len(nums)+1)
for i in range(0,len(nums)):
self._nums[i+1] = self._nums[i] + nums[i]
def sumRange(self, i: int, j: int) -> int:
return self._nums[j+1] - self._nums[i]
运行结果:
分析:
观察题目,其实sumRange(j, i)的和,可以通过[0, i]的和,减去[0, j-1]的和,因此, 只要先存储整个列表各个位置的累计和,最后根据题目需要,调用这两部分的和相减即可。
前面的各位置累计和只需要算一次,后面的调用,时间复杂度都为O(1)。
总结:
这道题可以帮我们加深对动态规划理念的认识。动态规划最首要的特征是使用缓存,之后才是转移方程。