前言
欢迎大家积极在评论区留言发表自己的看法,知无不言,言无不尽,养成每天刷题的习惯,也可以自己发布优质的解题报告,供社区一同鉴赏,吸引一波自己的核心粉丝。
今天是五月集训第八天:前缀和
一、练习题目
1480.一维数组的动态和
1588.所有奇数长度子数组的和
1442. 形成两个异或相等数组的三元组数目
1094. 拼车
二、算法思路
- 1、1480.一维数组的动态和:就利用前缀和。
- 2、1588.所有奇数长度子数组的和:这个题目感觉对我来说并不是一道简单题,想了很久才逐渐理清了思路。我能理解的思考写法在下面源码剖析中。
具体过程:
1.拿[1,4,2,5,3]
举例,用一个sum数组表示前缀和,sum求出来是[0,1,5,7,12,15]
;
2.定义i扫描原数组,定义j从i+1开始,每次j += 2
,意图是找i开始奇数长度度的子数组,看上面的例子,j就是+1,+3,+5往后走;
3.我们提前算好了前缀和,那比如我i = 0
,j = i + 1
就是从i开始1长度的奇数数组[1],刚好也是sum[j] - sum[i] = 1
,然后j = i + 3
就是i开始长度为3的奇数数组[1,4,2],刚好也是sum[j] - sum[i] = 7
,后面就依次类推就行了,可以草稿纸复现一下。 - 3、1442. 形成两个异或相等数组的三元组数目:前缀和+哈希表。
- 4、1094.拼车:巧妙的前缀和。
三、源码剖析
// 1480.一维数组的动态和
class Solution {
public:
vector<int> runningSum(vector<int>& nums) {
int n = nums.size();
for (int i = 1; i < n; i++)
{
nums[i] += nums[i - 1]; //(1)
}
return nums;
}
- 1、利用前缀和直接在原数组操作。
// 1588.所有奇数长度子数组的和
class Solution {
public:
int sumOddLengthSubarrays(vector<int>& arr) {
int n = arr.size(), ans = 0;
vector<int> sum(n + 1);
for(int i = 0; i < n; i++) {
sum[i + 1] = sum[i] + arr[i]; // (1)
}
for(int i = 0; i < n; i++) {
for(int j = i + 1; j <= n; j += 2) { //(2)
ans += sum[j] - sum[i]; //(3)
}
}
return ans;
}
};
- 1、用一个sum数组表示前缀和;
- 2、定义i扫描原数组,定义j从i+1开始,每次
j += 2
,意图是找i开始奇数长度度的子数组,j就是+1,+3,+5,……+奇数往后走; - 3、加到ans里面。
// 1442. 形成两个异或相等数组的三元组数目
class Solution {
unordered_map<int, int> hash;
public:
int countTriplets(vector<int>& arr) {
int pre, ans = 0, n = arr.size();
for(int i = 1; i < n; i++) {
arr[i] = arr[i - 1] ^ arr[i]; //(1)
}
for(int j = 1; j < n; ++j) {
hash.clear();
for(int i = 0; i < j; ++i) { //(2)
if(i == 0) {
pre = 0;
} else {
pre = arr[i - 1];
}
++hash[arr[j - 1] ^ pre];
}
for(int k = j; k < n; ++k) { //(3)
ans += hash[arr[k] ^ arr[j - 1]];
}
}
return ans;
}
};
- 1、计算前缀和
- 2、枚举一个j,再枚举一个i将异或和[i,j-1]塞入哈希表;
- 3、再去枚举k,去哈希表中查找[j,k]的异或和并累加。
// 1094. 拼车
class Solution {
public:
bool carPooling(vector<vector<int>>& trips, int capacity) {
int n = trips.size(), numPassengers[1001];
memset(numPassengers, 0, sizeof(numPassengers));
for(int i = 0; i < n; ++i) {
int cnt = trips[i][0];
int l = trips[i][1];
int r = trips[i][2];
numPassengers[l] += cnt;
numPassengers[r] -= cnt;
} //(1)
int sum = 0;
for(int i = 0; i < 1000; i++) {
sum += numPassengers[i];
if(sum > capacity) { //(2)
return false;
}
}
return true;
}
};
- 1、用一个数组来标记上下车的情况,线性扫描置上标记;
- 2、累加标记,当前时间点列车上的人数,如果超过给定值,返回false,否则true。