前缀和与差分数组
Posted 编程异思坊
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前缀和与差分数组相关的知识,希望对你有一定的参考价值。
前缀和与差分数组
基本概念
- 前缀和
我们有一个数组,如果我们要知道区间 [L, R] 的和,通常的做法是遍历一遍;这种做法在访问次数比较少的情况下或许可以,但是当我们需要多次访问时,若访问 m 次,时间复杂度为 O(m * n)。
而利用前缀和(空间换时间的方式),构造一个数组 sum,数组元素记录该索引之前(包括该索引)的数组元素之和。我们只需要通过 sum[R] - sum[L - 1]
就能求出指定范围之和。若访问 m 次,时间复杂度为 O(m)。
for (int i = 1; i <= n; i++) {
sum[i] = sum[i - 1] + arr[i];
}
- 差分数组
如果我们需要对数组的一个区间进行频繁增减,通常的做法是在遍历的同时进行增减,这种做法的时间复杂度为 O(N)。而引入差分数组,我们只需要的时间复杂度为 O(1)。
for (int i = 1; i < n; i++) {
diff[i] = nums[i] - nums[i - 1];
}
Leetcode 例题
303.区域和检索-数组不可变
思路解析:
我们自己定义一个数组 sums,将 sums[0] 设为 0,sums[i] 表示从 num[0] 到 num[i - 1] 累加和。
class NumArray {
public:
vector<int> sums;
NumArray(vector<int>& nums) {
int len = nums.size();
sums.resize(len + 1);
for (int i = 1; i <= len; i++) {
sums[i] = sums[i - 1] + nums[i - 1];
}
}
int sumRange(int left, int right) {
return sums[right + 1] - sums[left];
}
};
思路解析:
pre[j - 1] == pre[i] - k
我们考虑以 i 结尾的和为 k 的连续子数组个数时只要统计有多少个前缀和为 pre[i] - k 的 pre[j] 即可。我们建立哈希表 mp,以和为键,出现次数为对应的值,记录 pre[i] 出现的次数,从左往右边更新 mp 边计算答案,那么以 i 结尾的答案 mp[pre[i]−k] 即可在 O(1) 时间内得到。最后的答案即为所有下标结尾的和为 k 的子数组个数之和。
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
unordered_map<int, int> hash;
int sum = 0, cnt = 0;
hash[0] = 1;
for (int i = 0; i < nums.size(); i++) {
sum += nums[i];
if (hash[sum - k]) cnt += hash[sum - k];
hash[sum]++;
}
return cnt;
}
};
思路解析:
负雪明烛题解
class NumMatrix {
public:
vector<vector<int>>preSum;
NumMatrix(vector<vector<int>>& matrix) {
if(matrix.empty()){
return ;
}
int n=matrix.size();
int m=matrix[0].size();
preSum.resize(n+1);
for(int i=0;i<n+1;i++){
preSum[i].resize(m+1);
}
if (n> 0) {
for (int i = 0; i <n; i++) {
for (int j = 0; j <m; j++) {
preSum[i+1][j+1] = preSum[i][j+1] + preSum[i+1][j] - preSum[i][j] + matrix[i][j];
}
}
}
}
int sumRegion(int row1, int col1, int row2, int col2) {
return preSum[row2 + 1][col2 + 1] - preSum[row2 + 1][col1] - preSum[row1][col2 + 1] + preSum[row1][col1];
}
};
class Solution {
public:
bool carPooling(vector<vector<int>>& trips, int capacity) {
if (trips.empty()) {
return false;
}
const int MAX_PASSNUM = 1001;
vector<int> changeNum(MAX_PASSNUM, 0);
for (int i = 0; i < trips.size(); i++) {
changeNum[trips[i][1]] += trips[i][0];
changeNum[trips[i][2]] -= trips[i][0];
}
int sum = 0;
for (int j = 0; j < changeNum.size(); j++) {
sum += changeNum[j];
if (sum > capacity) {
return false;
}
}
return true;
}
};
class Solution {
public:
vector<int> corpFlightBookings(vector<vector<int>>& bookings, int n) {
vector<int> relust(n+1, 0);
int diff = 0;
for(int i = 0; i < bookings.size(); i++){
int k = bookings[i][0]-1;
diff = bookings[i][2];
relust[k] += diff;
int j = bookings[i][1];
relust[j] -= diff;
}
for(int i = 1; i < n; i++){
relust[i] += relust[i-1];
}
relust.pop_back();
return relust;
}
};
以上是关于前缀和与差分数组的主要内容,如果未能解决你的问题,请参考以下文章