目录
差分与前缀和作为常见的数据结构,经常用来处理区间变化的问题。前缀和与哈希表、差分而前缀和这两种搭配经常一起出现。
前缀和
前缀和原理
前缀和,即前i项和。当我们得到一个数组nums,假设数组prefix[i]表示nums数组中的前i项和,于是有:
prefix[0]=nums[0]
prefix[1]=nums[0]+nums[1]=prefix[0]+nums[1]
prefix[2]=nums[0]+nums[1]+nums[2]=prefix[1]+nums[2]
……
prefix[n]=prefix[n-1]+nums[n]
数组prefix就是数组nums的前缀和。
前缀和有什么用呢?
在处理区间问题时,我们可以通过在前缀和数组上做减法,很容易的得到特定区间的总和,如:
prefix[5]=nums[0]+nums[1]+……nums[5]
prefix[10]=nums[0]+nums[1]+……nums[10]
prefix[10]-prefix[5]=nums[6]+nums[7]+……+nums[10]
依据前缀和的这个特性,在一些情境下,前缀和能把复杂的问题简单化。
接下来会以例题的形式,介绍几种前缀和常见的用法。
简单的一维前缀和
题目来源:1749. 任意子数组和的绝对值的最大值 - 力扣(LeetCode)
题目:
给你一个整数数组 nums。一个子数组 [nums[l], nums[l+1], ..., nums[r-1], nums[r] 的和的绝对值为 abs(nums[l] + nums[l+1] + ... + nums[r-1] + nums[r]) 。
请你找出 nums 中 和的绝对值 最大的任意子数组(可能为空),并返回该 最大值 。
示例 1:
输入:nums = [1,-3,2,3,-4]
输出:5
解释:子数组 [2,3] 和的绝对值最大,为 abs(2+3) = abs(5) = 5 。
示例 2:
输入:nums = [2,-5,1,-4,3,-2]
输出:8
解释:子数组 [-5,1,-4] 和的绝对值最大,为 abs(-5+1-4) = abs(-8) = 8 。
解题思路:
这是一道典型的前缀和,题干要求某个区间的和,使得该区间的和绝对值最大。我们可以建立一个前缀和数组prefix,再通过遍历prefix数组,下标位置靠后的元素减去下标靠前的元素,得到区间的和。
Code:
int maxAbsoluteSum(vector<int>& nums) {
int n=nums.size();
vector<int>prefix(n+1);
for(int i=0;i<n;i++){
prefix[i+1]=prefix[i]+nums[i];
}
int mx=0,mn=0,ans=0;
for(int i=1;i<=n;i++){
int tmp=max(abs(prefix[i]-mx),abs(prefix[i]-mn));
ans=max(ans,tmp);
mx=max(mx,prefix[i]);
mn=min(mn,prefix[i]);
}
return ans;
}
def maxAbsoluteSum(self, nums: List[int]) -> int:
ans=mn=mx=0
for x in nums:
mn=min(mn,0)+x
mx=max(mx,0)+x
ans=max(ans,mx,-mn)
return ans
前缀和与哈希表
前缀和常常和哈希表一起出现,哈希表用于记录每次前缀和运算的结果的次数(或其他)。
题目来源:974. 和可被 K 整除的子数组 - 力扣(LeetCode)
题目:
给定一个整数数组 nums 和一个整数 k ,返回其中元素之和可被 k 整除的非空 子