📅  最后修改于: 2023-12-03 15:07:17.446000             🧑  作者: Mango
前缀和数组是一种常用的数据结构,是数组的一种预处理方式。它的主要应用场景是统计一段连续区间的和,对于竞争性编程而言,前缀和数组也是一种强大的工具,通过它可以实现很多常见的问题,例如区间求和、区间奇偶判断等。
前缀和数组的实现方式很简单,我们只需要将原数组中的元素依次累加,得到一个新的数组,新数组中的每一个元素就是原数组中前n个元素的和,其中n表示新数组的下标。代码如下:
vector<int> prefixSum(vector<int>& nums) {
int n = nums.size();
vector<int> sums(n + 1, 0);
for (int i = 1; i <= n; i++) {
sums[i] = sums[i - 1] + nums[i - 1];
}
return sums;
}
前缀和数组最常见的应用场景就是区间求和,这也是前缀和数组最初的设计初衷。对于原数组中任意一个区间[l, r],只需要用前缀和数组中下标为r+1的元素减去下标为l的元素即可得到区间[l, r]的和。代码如下:
int rangeSum(vector<int>& nums, int l, int r) {
vector<int> sums = prefixSum(nums);
return sums[r + 1] - sums[l];
}
如果要判断一个数组中的任意一个区间[l,r]中奇数的个数是偶数还是奇数,可以用前缀和数组来实现。只需要用前缀和数组中下标为r+1的元素减去下标为l的元素,得到区间[l,r]中的元素个数k,如果k为偶数,则区间[l,r]中的奇数个数也为偶数,否则为奇数。代码如下:
bool isOddNumber(vector<int>& nums, int l, int r) {
vector<int> sums = prefixSum(nums);
return (sums[r + 1] - sums[l]) % 2 != 0;
}
子数组最大和是一个经典的问题,在竞争性编程中也是一个常见的问题。可以用前缀和数组来解决这个问题,首先我们需要先计算出数组中的所有连续子数组的和,然后找出其中的最大值即可。代码如下:
int maxSubArray(vector<int>& nums) {
int n = nums.size();
vector<int> sums(n + 1, 0);
for (int i = 1; i <= n; i++) {
sums[i] = sums[i - 1] + nums[i - 1];
}
int ans = INT_MIN, minSum = 0;
for (int i = 1; i <= n; i++) {
ans = max(ans, sums[i] - minSum);
minSum = min(minSum, sums[i]);
}
return ans;
}
前缀和数组是竞争性编程中很有用的一种数据结构,它可以帮助我们有效地解决很多问题,例如区间求和、区间奇偶判断、子数组最大和等问题。只需要对原数组进行一次预处理,就可以在O(1)的时间内回答很多问题,极大地提高了算法的效率。