前言
提示:这里可以添加本文要记录的大概内容:
记录一下算法学习过程
提示:以下是本篇文章正文内容,下面案例可供参考
一、一维数组中的前缀和前缀和
前缀和技巧适用于快速、频繁地计算一个索引区间内的元素之和。
二、题目
三、解答过程
题目要求你实现这样一个类:
class NumArray {
public:
NumArray(vector<int>& nums) {}
/* 查询闭区间 [left, right] 的累加和 */
int sumRange(int left, int right) {}
};
sumRange 函数需要计算并返回一个索引区间之内的元素和,没学过前缀和的人可能写出如下代码:
class NumArray {
private:
vector<int> nums;
public:
NumArray(vector<int>& nums) {
this->nums = nums;
}
int sumRange(int left, int right) {
int res = 0;
for (int i = left; i <= right; i++) {
res += nums[i];
}
return res;
}
};
这样,可以达到效果,但是效率很差,因为 sumRange 方法会被频繁调用,而它的时间复杂度是 O(N),其中 N 代表 nums 数组的长度。
最优解法是使用前缀和技巧,将 sumRange 函数的时间复杂度降为 O(1),也就是不要在 sumRange 里面用 for 循环。
代码实现:
class NumArray {
private:
// 前缀和数组
vector<int> preSum;
public:
/* 输入一个数组,构造前缀和 */
NumArray(vector<int>& nums) {
// preSum[0] = 0,便于计算累加和
preSum.resize(nums.size() + 1);
// 计算 nums 的累加和
for (int i = 1; i < preSum.size(); i++) {
preSum[i] = preSum[i - 1] + nums[i - 1];
}
}
/* 查询闭区间 [left, right] 的累加和 */
int sumRange(int left, int right) {
return preSum[right + 1] - preSum[left];//这里其实可以观察nums的累加和部分代码,其中 preSum[i] = preSum[i - 1] + nums[i - 1];简单的代数运算即可得出nums[i]=preSum[i + 1] - preSum[i]
}
};
也就是new一个新的数组preSum出来,preSum[i]记录了nums[0,…i-1]的累加和,然后在给定的区间[left,right]中计算nums的和就可以通过preSum[right+1]-presum[left]
如果想要求索引区间[1,4]的累加和,就可以用preSum[5]-preSum[1]