一、题目
给定一个整数数组 nums
,求出数组从索引 i
到 j
(i ≤ j
)范围内元素的总和,包含 i
、j
两点。
二、解析
题目很简单,如果直接暴力法,即存储数组 nums的值,每次调用 sumRange 时,通过循环的方法计算数组 nums 从下标 i 到下标 j 范围内的元素和,需要计算 j−i+1个元素的和。由于每次检索的时间和检索的下标范围有关,因此检索的时间复杂度较高,如果检索次数较多,则会超出时间限制。
class NumArray {
public:
vector<int> m_matrix;
NumArray(vector<int>& nums) {
m_matrix = nums;
}
int sumRange(int i, int j) {
int sum = 0;
for (int m = 0; m < m_matrix.size(); m++)
if (m >= i && m <= j)
sum += m_matrix[m]; // 直接遍历,计算和,运行缓慢
return sum;
}
};
由于会进行多次检索,即多次调用 sumRang,因此为了降低检索的总时间,应该降低 sumRange 的时间复杂度,最理想的情况是时间复杂度 O(1)。为了将检索的时间复杂度降到 O(1),需要在初始化的时候进行预处理。注意到当 i≤j 时,sumRange(i,j) 可以写成如下形式
由此可知,要计算 sumRange(i,j),则需要计算数组 nums在下标 j 和下标 i−1的前缀和,然后计算两个前缀和的差。
如果可以在初始化的时候计算出数组nums 在每个下标处的前缀和,即可满足每次调用 sumRange的时间复杂度都是 O(1)。
三、代码
class NumArray {
public:
vector<int> sums;
NumArray(vector<int>& nums) {
int n = nums.size();
sums.resize(n + 1);
for (int i = 0; i < n; i++) {
sums[i + 1] = sums[i] + nums[i]; //计算每个元素对应的和
}
}
int sumRange(int i, int j) {
return sums[j + 1] - sums[i]; // j 对应j+1 ,i-1对应 i,求差
}
};
参考: