- 前缀和,就是定义pre 为nums的前i个元素的和值,一般pre数组长度会=n+1,如许在计算的nums数组中下标i到j的情况的时候,直接就可以使用pre[j+1]-pre,如果找的是第i个到第j个,那么就是pre[j]-pre[i-1]
- 转化为第几个会好明白一点
- 以是得根据题目求解的是下标照旧第几个确定详细的计算公式
- 前缀和与哈希表:留意第一个元素是否加入哈希表!
- 二维前缀和: 求解下标为(x1,y1),(x2,y2)二维区间之间的区间和,转化为第几个,那么对应的公式就是ans = pre[x2+1][y2+1] - pre[x1][y2+1] - pre[x2+1][y1] + pre[x1][y1],开始的时候求解的区间前缀的公式是pre[i+1][j+1] = pre[j+1] + pre[i+1][j] - pre[j] + nums[j]
前缀和基础
3427.变宗子数组求和
3427.变宗子数组求和
- 求解的是下标题目,以是是pre[j+1] - pre范例
- class Solution:
- def subarraySum(self, nums: List[int]) -> int:
- # 前缀和的问题
- n = len(nums)
- pre = [0]*(n+1)
- for i in range(n):
- pre[i+1] = pre[i] + nums[i]
- ans = 0
- for i in range(n):
- start = max(0,i-nums[i])
- ans += pre[i+1] - pre[start]
- return ans
复制代码 前缀和与哈希表
1524.和为奇数的子数组数目
1524.和为奇数的子数组数目
- 使用哈希表+前缀和,要留意这个前缀和的第一个也要加入哈希表!
- class Solution:
- def numOfSubarrays(self, arr: List[int]) -> int:
- # 直接用哈希表存储
- mod = 10**9 + 7
- store = [0,0]
- n = len(arr)
- # 使用前缀和
- pre = [0]*(n+1)
- for i in range(n):
- pre[i+1] = pre[i] + arr[i]
- ans = 0
- for i in range(n+1):
- if pre[i] % 2==0:
- ans = ans + store[1]
- store[0] = store[0] + 1
- else:
- ans = ans + store[0]
- store[1] = store[1] + 1
- return ans % mod
复制代码 距离和
1685.有序数组中绝对值之和
1685.有序数组中绝对值之和
- 由于是有序的,以是计算的公式可以拆开,然后就会发现很多得使用到区间和的题目
博主分析
- class Solution:
- def getSumAbsoluteDifferences(self, nums: List[int]) -> List[int]:
- # 由于是有序的,所以可以考虑直接拆分公式,然后使用前缀和
- # 原本情况下,nums[i] - nums[j] 前面的情况,当 i的时候,前面有i个也就是
- # nums[i] * i - 前 nums[0] + ··· + nums[i-1] 也就是 pre[i]
- # n - 1 - (i+1) + 1 = n - i -1 个
- # 后续的情况就是 nums[j] - nums[i] ,也就是 nums[i+1] + ··· + nums[n-1] -
- # 第 i + 2个
- n = len(nums)
- pre = [0]*(n+1)
- for i in range(n):
- pre[i+1] = pre[i] + nums[i]
- ans = [0]*n
- for i in range(n):
- ans[i] = i * nums[i] - pre[i] - (n-i-1)* nums[i] + pre[n] - pre[i+1]
- return ans
复制代码 前缀异或和
1177.构建回文串检测
1177.构建回文串检测
- 可以看到,是求解区间的情况,并且可以重新分列,并且是最多K次更换成任何小写英文字母,对于回文串的题目,由于是可以重新分列,以是我们得统计每种字母出现的次数,因为当字母出现的次数是偶数的时候,我们就可以对称分布,当是奇数的时候,如果出现一个奇数,那我们可以直接放最中心,如果出现2个奇数,就得改变此中一个即可,以此类推我们只需统计区间内26个字母出现的奇数的次数num,那么对应效果就是num//2
- class Solution:
- def canMakePaliQueries(self, s: str, queries: List[List[int]]) -> List[bool]:
- # 使用前缀和计算 26种字母出现的次数
- n = len(s)
- pre = [[0]*26 for i in range(n+1)]
- # 计数方式
- for i in range(n):
- tar = ord(s[i]) - ord("a")
- for j in range(26):
- if j == tar:
- pre[i+1][j] = pre[i][j] + 1
- else:
- pre[i+1][j] = pre[i][j]
- # 统计完成
- # 开始遍历
- m = len(queries)
- ans = [0]*m
- for i in range(m):
- odd = 0
- left,right,k = queries[i][0],queries[i][1],queries[i][2]
- for j in range(26):
- # left 是下标,也就是第left+1个,那么就是对应pre[left],right是对应这个第right+1个,pre[right+1]
- if (pre[right+1][j]%2 == 1 and pre[left][j]%2 == 0) or (pre[right+1][j]%2 == 0 and pre[left][j]%2 == 1):
- odd += 1
- # 判断是否超过可以修改的次数
- if odd // 2 <= k:
- ans[i] = True
- else:
- ans[i] = False
- return ans
复制代码
- 当然,这个奇数偶数的情况实在可以用异或的情况表现,也就是开始的时候都是0,但是该字母出现一次的时候,我们就用上一个次数前缀和异或1,否则就是异或0
- class Solution:
- def canMakePaliQueries(self, s: str, queries: List[List[int]]) -> List[bool]:
- # 使用前缀和计算 26种字母出现的次数
- n = len(s)
- pre = [[0]*26 for i in range(n+1)]
- # 计数方式
- for i in range(n):
- tar = ord(s[i]) - ord("a")
- for j in range(26):
- if j == tar:
- pre[i+1][j] = pre[i][j] ^ 1
- else:
- pre[i+1][j] = pre[i][j] ^ 0
- # 统计完成
- # 开始遍历
- m = len(queries)
- ans = [0]*m
- for i in range(m):
- odd = 0
- left,right,k = queries[i][0],queries[i][1],queries[i][2]
- for j in range(26):
- # left 是下标,也就是第left+1个,那么就是对应pre[left],right是对应这个第right+1个,pre[right+1]
- #if (pre[right+1][j]%2 == 1 and pre[left][j]%2 == 0) or (pre[right+1][j]%2 == 0 and pre[left][j]%2 == 1):
- if pre[right+1][j]%2 ^ pre[left][j]%2 == 1:
- odd += 1
- # 判断是否超过可以修改的次数
- if odd // 2 <= k:
- ans[i] = True
- else:
- ans[i] = False
- return ans
复制代码 其他一维前缀和
1310.子数组异或查询
1310.子数组异或查询
- 异或的性质要掌握 a^b = k,那么就可以推出a = k ^ b
- 只需纪录异或前缀即可,就类似于正常的求解区间和一样
- class Solution:
- def xorQueries(self, arr: List[int], queries: List[List[int]]) -> List[int]:
- # 前缀异或和
- n = len(arr)
- pre = [0]*(n+1)
- for i in range(n):
- # pre[i] 表示前i个元素的异或和
- pre[i+1] = pre[i] ^ arr[i]
- m = len(queries)
- ans = [0]*m
- for i in range(m):
- left,right = queries[i][0],queries[i][1]
- # 对应的是第left+1到right+1的异或区间值,对应就是pre[right+1] - pre[left]
- ans[i] = pre[right+1] ^ pre[left]
- return ans
复制代码 二维前缀和
1314.矩阵地区和
1314.矩阵地区和
- class Solution:
- def matrixBlockSum(self, mat: List[List[int]], k: int) -> List[List[int]]:
- # 二维区间前缀和
- m,n = len(mat),len(mat[0])
- # 肯定不可能按照题目的意思直接构造
- # 还是按照二维前缀和的思想,求解答案
- pre = [[0]*(n+1) for _ in range(m+1)]
- for i in range(m):
- for j in range(n):
- # pre[i][j] 表示i列,前j行所围成的区间和
- pre[i+1][j+1] = pre[i+1][j] + pre[i][j+1] - pre[i][j] + mat[i][j]
- # 求解完,然后进行求解答案
- ans = [[0]*n for i in range(m)]
- for i in range(m):
- for j in range(n):
- # 先求解出下标的问题
- x1,x2 = max(0,i-k),min(m-1,i+k)
- y1,y2 = max(0,j-k),min(n-1,j+k)
- # 这个是下标问题,所以是对应的是
- ans[i][j] = pre[x2+1][y2+1] - pre[x2+1][y1] - pre[x1][y2+1] + pre[x1][y1]
- return ans
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |