当前位置: 首页 > news >正文

前缀和基础训练

选自灵神题单,前缀和基础1.1 。

303. 区域和检索 - 数组不可变

给定一个整数数组 nums,处理以下类型的多个查询:

  1. 计算索引 leftright (包含 leftright)之间的 nums 元素的 ,其中 left <= right

实现 NumArray 类:

  • NumArray(int[] nums) 使用数组 nums 初始化对象
  • int sumRange(int i, int j) 返回数组 nums 中索引 leftright 之间的元素的 总和 ,包含 leftright 两点(也就是 nums[left] + nums[left + 1] + ... + nums[right] )

示例 1:

输入:
["NumArray", "sumRange", "sumRange", "sumRange"]
[[[-2, 0, 3, -5, 2, -1]], [0, 2], [2, 5], [0, 5]]
输出:
[null, 1, -1, -3]解释:
NumArray numArray = new NumArray([-2, 0, 3, -5, 2, -1]);
numArray.sumRange(0, 2); // return 1 ((-2) + 0 + 3)
numArray.sumRange(2, 5); // return -1 (3 + (-5) + 2 + (-1)) 
numArray.sumRange(0, 5); // return -3 ((-2) + 0 + 3 + (-5) + 2 + (-1))

class NumArray:def __init__(self, nums: List[int]):self.s = [0] * (len(nums) + 1)	# 前缀和数组,多加1是为了防止下面的循环越界# 可以将前缀和数组的下标看成是第“i”个数字,元素个数“i”从1开始for i, x in enumerate(nums):self.s[i + 1] = self.s[i] + xdef sumRange(self, left: int, right: int) -> int:return self.s[right + 1] - self.s[left]# Your NumArray object will be instantiated and called as such:
# obj = NumArray(nums)
# param_1 = obj.sumRange(left,right)


3427. 变长子数组求和

给你一个长度为 n 的整数数组 nums 。对于 每个 下标 i0 <= i < n),定义对应的子数组 nums[start ... i]start = max(0, i - nums[i]))。

返回为数组中每个下标定义的子数组中所有元素的总和。

子数组 是数组中的一个连续、非空 的元素序列。

示例 1:

输入: nums = [2,3,1]

输出: 11

解释:

下标 i子数组
0nums[0] = [2]2
1nums[0 ... 1] = [2, 3]5
2nums[1 ... 2] = [3, 1]4
总和11

总和为 11 。因此,输出 11 。

示例 2:

输入: nums = [3,1,1,2]

输出: 13

解释:

下标 i子数组
0nums[0] = [3]3
1nums[0 ... 1] = [3, 1]4
2nums[1 ... 2] = [1, 1]2
3nums[1 ... 3] = [1, 1, 2]4
总和13

总和为 13 。因此,输出为 13 。


class Solution:def subarraySum(self, nums: List[int]) -> int:pre = [0] * (len(nums) + 1)     # 前缀和数组s = 0for i, x in enumerate(nums):pre[i + 1] = pre[i] + xfor i, x in enumerate(nums):s += pre[i + 1] - pre[max(0, i - x)]return s


2559. 统计范围内的元音字符串数

给你一个下标从 0 开始的字符串数组 words 以及一个二维整数数组 queries

每个查询 queries[i] = [li, ri] 会要求我们统计在 words 中下标在 liri 范围内(包含 这两个值)并且以元音开头和结尾的字符串的数目。

返回一个整数数组,其中数组的第 i 个元素对应第 i 个查询的答案。

注意: 元音字母是 'a''e''i''o''u'

示例 1:

输入:words = ["aba","bcb","ece","aa","e"], queries = [[0,2],[1,4],[1,1]]
输出:[2,3,0]
解释:以元音开头和结尾的字符串是 "aba"、"ece"、"aa" 和 "e" 。
查询 [0,2] 结果为 2(字符串 "aba" 和 "ece")。
查询 [1,4] 结果为 3(字符串 "ece"、"aa"、"e")。
查询 [1,1] 结果为 0 。
返回结果 [2,3,0] 。

示例 2:

输入:words = ["a","e","i"], queries = [[0,2],[0,1],[2,2]]
输出:[3,2,1]
解释:每个字符串都满足这一条件,所以返回 [3,2,1] 。

class Solution:def vowelStrings(self, words: List[str], queries: List[List[int]]) -> List[int]:pre = [0] * (len(words) + 1)    # 前缀和数组for i, w in enumerate(words):pre[i + 1] = pre[i]if w[0] in "aeiou" and w[-1] in "aeiou":pre[i + 1] += 1ans = []for q in queries:ans.append(pre[q[1] + 1] - pre[q[0]])return ans


3152. 特殊数组 II

如果数组的每一对相邻元素都是两个奇偶性不同的数字,则该数组被认为是一个 特殊数组

你有一个整数数组 nums 和一个二维整数矩阵 queries,对于 queries[i] = [fromi, toi],请你帮助你检查

nums[fromi..toi] 是不是一个 特殊数组

返回布尔数组 answer,如果 nums[fromi..toi] 是特殊数组,则 answer[i]true ,否则,answer[i]false

示例 1:

输入: nums = [3,4,1,2,6], queries = [[0,4]]

输出:[false]

解释:

子数组是 [3,4,1,2,6]。2 和 6 都是偶数。

示例 2:

输入: nums = [4,3,1,6], queries = [[0,2],[2,3]]

输出:[false,true]

解释:

  1. 子数组是 [4,3,1]。3 和 1 都是奇数。因此这个查询的答案是 false
  2. 子数组是 [1,6]。只有一对:(1,6),且包含了奇偶性不同的数字。因此这个查询的答案是 true
class Solution:def isArraySpecial(self, nums: List[int], queries: List[List[int]]) -> List[bool]:# 前缀和记录[0,i]有多少个数字发生奇偶变化pre = [0] * (len(nums))for i in range(1, len(nums)):pre[i] = pre[i - 1]# 如果与前面的数字相比较,奇偶性不同,则增加一个变化if nums[i] % 2 != nums[i - 1] % 2:pre[i] += 1ans = [False] * len(queries)for i, (l, r) in enumerate(queries):# 计算[l+1,r]之间的奇偶性变化的次数个数是否与nums[r+1,l]个数相同# 不算nums[r]是因为数组只有一个元素时,奇偶不变化if pre[r] - pre[l] == r - l:ans[i] = Truereturn ans


1749. 任意子数组和的绝对值的最大值

给你一个整数数组 nums 。一个子数组 [numsl, numsl+1, ..., numsr-1, numsr]和的绝对值abs(numsl + numsl+1 + ... + numsr-1 + numsr)

请你找出 nums和的绝对值 最大的任意子数组(可能为空),并返回该 最大值

abs(x) 定义如下:

  • 如果 x 是负整数,那么 abs(x) = -x
  • 如果 x 是非负整数,那么 abs(x) = x

示例 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 。

class Solution:def maxAbsoluteSum(self, nums: List[int]) -> int:s1 = [0] * (len(nums) + 1)for i, x in enumerate(nums):s1[i + 1] = s1[i] + x# 子数组和的绝对值等于abs(s[j]-s[i])# 所以要让两者之差尽可能大return max(s1) - min(s1)


2389. 和有限的最长子序列

给你一个长度为 n 的整数数组 nums ,和一个长度为 m 的整数数组 queries

返回一个长度为 m 的数组 answer ,其中 answer[i]nums 中 元素之和小于等于 queries[i]子序列最大 长度 。

子序列 是由一个数组删除某些元素(也可以不删除)但不改变剩余元素顺序得到的一个数组。

示例 1:

输入:nums = [4,5,2,1], queries = [3,10,21]
输出:[2,3,4]
解释:queries 对应的 answer 如下:
- 子序列 [2,1] 的和小于或等于 3 。可以证明满足题目要求的子序列的最大长度是 2 ,所以 answer[0] = 2 。
- 子序列 [4,5,1] 的和小于或等于 10 。可以证明满足题目要求的子序列的最大长度是 3 ,所以 answer[1] = 3 。
- 子序列 [4,5,2,1] 的和小于或等于 21 。可以证明满足题目要求的子序列的最大长度是 4 ,所以 answer[2] = 4 。

示例 2:

输入:nums = [2,3,4,5], queries = [1]
输出:[0]
解释:空子序列是唯一一个满足元素和小于或等于 1 的子序列,所以 answer[0] = 0 。

class Solution:def answerQueries(self, nums: List[int], queries: List[int]) -> List[int]:# 由题目中的子序列和求和可以推出答案与元素顺序无关,所以可以排序(注意不是子数组,子数组就不能排序)# 排序后由于我们要让子序列的长度尽可能大,所以可以从第一个元素开始计算nums.sort()pre = [0] * (len(nums) + 1)for i, x in enumerate(nums):pre[i + 1] = pre[i] + xans = []for q in queries:ans.append(bisect_right(pre, q) - 1)return ans


3361. 两个字符串的切换距离

给你两个长度相同的字符串 st ,以及两个整数数组 nextCostpreviousCost

一次操作中,你可以选择 s 中的一个下标 i ,执行以下操作 之一

  • s[i] 切换为字母表中的下一个字母,如果 s[i] == 'z' ,切换后得到 'a' 。操作的代价为 nextCost[j] ,其中 j 表示 s[i] 在字母表中的下标。
  • s[i] 切换为字母表中的上一个字母,如果 s[i] == 'a' ,切换后得到 'z' 。操作的代价为 previousCost[j] ,其中 js[i] 在字母表中的下标。

切换距离 指的是将字符串 s 变为字符串 t最少 操作代价总和。

请你返回从 st切换距离

示例 1:

输入: s = “abab”, t = “baba”, nextCost = [100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], previousCost = [1,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]

输出: 2

解释:

  • 选择下标 i = 0 并将 s[0] 向前切换 25 次,总代价为 1 。
  • 选择下标 i = 1 并将 s[1] 向后切换 25 次,总代价为 0 。
  • 选择下标 i = 2 并将 s[2] 向前切换 25 次,总代价为 1 。
  • 选择下标 i = 3 并将 s[3] 向后切换 25 次,总代价为 0 。

示例 2:

**输入:**s = “leet”, t = “code”, nextCost = [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], previousCost = [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]

输出: 31

解释:

  • 选择下标 i = 0 并将 s[0] 向前切换 9 次,总代价为 9 。
  • 选择下标 i = 1 并将 s[1] 向后切换 10 次,总代价为 10 。
  • 选择下标 i = 2 并将 s[2] 向前切换 1 次,总代价为 1 。
  • 选择下标 i = 3 并将 s[3] 向后切换 11 次,总代价为 11 。

class Solution:def shiftDistance(self, s: str, t: str, nextCost: List[int], previousCost: List[int]) -> int:pre = [0] * (26 * 2 + 1)  # 向前切换的前缀和nex = [0] * (26 * 2 + 1)  # 向后切换的前缀和for i in range(26 * 2 + 1):pre[i] = pre[i - 1] + previousCost[(i - 1) % 26]nex[i] = nex[i - 1] + nextCost[(i - 1) % 26]ans = 0for i, j in zip(s, t):if i == j:continues1 = ord(i) - 97s2 = ord(j) - 97# 建议在纸上模拟以下这两种情况且向前切换的代价与向后前后切换的代价if s1 < s2:# 向前切换的代价cost1 = pre[s1 + 26 + 1] - pre[s2 + 1]# 向后转换的代价cost2 = nex[s2] - nex[s1]else:cost1 = pre[s1 + 1] - pre[s2 + 1]cost2 = nex[s2 + 26] - nex[s1]ans += min(cost1, cost2)return ans


2055. 蜡烛之间的盘子

给你一个长桌子,桌子上盘子和蜡烛排成一列。给你一个下标从 0 开始的字符串 s ,它只包含字符 '*''|' ,其中 '*' 表示一个 盘子'|' 表示一支 蜡烛

同时给你一个下标从 0 开始的二维整数数组 queries ,其中 queries[i] = [lefti, righti] 表示 子字符串 s[lefti...righti]包含左右端点的字符)。对于每个查询,你需要找到 子字符串中两支蜡烛之间 的盘子的 数目 。如果一个盘子在 子字符串中 左边和右边 至少有一支蜡烛,那么这个盘子满足在 两支蜡烛之间

  • 比方说,s = "||**||**|*" ,查询 [3, 8] ,表示的是子字符串 "*||***\**\***|" 。子字符串中在两支蜡烛之间的盘子数目为 2 ,子字符串中右边两个盘子在它们左边和右边 至少有一支蜡烛。

请你返回一个整数数组 answer ,其中 answer[i] 是第 i 个查询的答案。

示例 1:

ex-1

输入:s = "**|**|***|", queries = [[2,5],[5,9]]
输出:[2,3]
解释:
- queries[0] 有两个盘子在蜡烛之间。
- queries[1] 有三个盘子在蜡烛之间。

示例 2:

ex-2

输入:s = "***|**|*****|**||**|*", queries = [[1,17],[4,5],[14,17],[5,11],[15,16]]
输出:[9,0,0,0,0]
解释:
- queries[0] 有 9 个盘子在蜡烛之间。
- 另一个查询没有盘子在蜡烛之间。

class Solution:def platesBetweenCandles(self, s: str, queries: List[List[int]]) -> List[int]:pre = [0] * (len(s) + 1)  # pre[i]表示[0,i-1]中有多少个盘子for i, x in enumerate(s):pre[i + 1] = pre[i]if x == "*":pre[i + 1] += 1left = [-1] * (len(s) + 1)  # 计算每个下标中左侧最近的蜡烛下标c = -1for i, x in enumerate(s):if s[i] == "|":c = ileft[i + 1] = cright = [len(s)] * (len(s) + 1)  # 计算每个下标中右侧最近的蜡烛下标c = len(s)for i in range(len(s) - 1, -1, -1):if s[i] == "|":c = iright[i + 1] = cans = []for l, r in queries:r = left[r + 1]  # 右边界l = right[l + 1]  # 左边界if l < r:   # 合法的边界# 计算[l,r]中有多少个盘子,就是计算s[l-1,r-1]中有多少个盘子(注意left与right数组向右扩展了一位)ans.append(pre[r] - pre[l])else:   # 说明里面没有盘子ans.append(0)return ans


1744. 你能在你最喜欢的那天吃到你最喜欢的糖果吗?

给你一个下标从 0 开始的正整数数组 candiesCount ,其中 candiesCount[i] 表示你拥有的第 i 类糖果的数目。同时给你一个二维数组 queries ,其中 queries[i] = [favoriteTypei, favoriteDayi, dailyCapi]

你按照如下规则进行一场游戏:

  • 你从第 0 天开始吃糖果。
  • 你在吃完 所有i - 1 类糖果之前,不能 吃任何一颗第 i 类糖果。
  • 在吃完所有糖果之前,你必须每天 至少一颗 糖果。

请你构建一个布尔型数组 answer ,用以给出 queries 中每一项的对应答案。此数组满足:

  • answer.length == queries.lengthanswer[i]queries[i] 的答案。
  • answer[i]true 的条件是:在每天吃 不超过 dailyCapi 颗糖果的前提下,你可以在第 favoriteDayi 天吃到第 favoriteTypei 类糖果;否则 answer[i]false

注意,只要满足上面 3 条规则中的第二条规则,你就可以在同一天吃不同类型的糖果。

请你返回得到的数组 answer

示例 1:

输入:candiesCount = [7,4,5,3,8], queries = [[0,2,2],[4,2,4],[2,13,1000000000]]
输出:[true,false,true]
提示:
1- 在第 0 天吃 2 颗糖果(类型 0),第 1 天吃 2 颗糖果(类型 0),第 2 天你可以吃到类型 0 的糖果。
2- 每天你最多吃 4 颗糖果。即使第 0 天吃 4 颗糖果(类型 0),第 1 天吃 4 颗糖果(类型 0 和类型 1),你也没办法在第 2 天吃到类型 4 的糖果。换言之,你没法在每天吃 4 颗糖果的限制下在第 2 天吃到第 4 类糖果。
3- 如果你每天吃 1 颗糖果,你可以在第 13 天吃到类型 2 的糖果。

示例 2:

输入:candiesCount = [5,2,6,4,1], queries = [[3,1,2],[4,10,3],[3,10,100],[4,100,30],[1,3,1]]
输出:[false,true,true,false,false]

class Solution:def canEat(self, candiesCount: List[int], queries: List[List[int]]) -> List[bool]:pre = [0] * (len(candiesCount) + 1)  # 吃了数量为区间[pre[i-1],pre[i]]颗糖果,一定能吃到第i个种类的糖果for i in range(len(candiesCount)):pre[i + 1] = pre[i] + candiesCount[i]ans = []for ft, fd, d in queries:# 到第fd天为止最多吃了多少颗糖果,且这个糖果数量大于pre[ft](pre[ft]表示前ft-1类的糖果数量)# 到第fd-1天为止最少吃了多少颗糖果且这个糖果数量一定要小于pre[ft+1](pre[ft+1]表示前ft类的糖果数量)# 注意题目给的fd从0开始if (fd + 1) * d > pre[ft] and fd < pre[ft + 1]:ans.append(True)else:ans.append(False)return ans


53. 最大子数组和

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

子数组是数组中的一个连续部分。

示例 1:

输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。

示例 2:

输入:nums = [1]
输出:1

示例 3:

输入:nums = [5,4,-1,7,8]
输出:23

class Solution:def maxSubArray(self, nums: List[int]) -> int:pre = [0] * (len(nums) + 1)for i, x in enumerate(nums):pre[i + 1] = pre[i] + xans = -inf  # 记录最大子数组和min_pre = 0  # 记录最小前缀和for i in range(1, len(pre)):# 更新答案,同时能保证最小前缀和一定在最大前缀和前面(至少包含一个元素)ans = max(ans, pre[i] - min_pre)min_pre = min(min_pre, pre[i])  # 最后再更新最小前缀和return ans


相关文章:

  • STM32H562----------ADC外设详解
  • Abaqus连接器弹片正向力分析:
  • MMAD论文精读
  • 【FAQ】HarmonyOS SDK 闭源开放能力 —Account Kit(5)
  • spring boot应答500问题跟踪
  • Docker基础命令
  • 图片组件|纯血鸿蒙组件库AUI
  • 小白的进阶之路系列之十一----人工智能从初步到精通pytorch综合运用的讲解第四部分
  • JS对数据类型的检测
  • 前端开发处理‘流式数据’与‘非流式数据’,在接收完整与非完整性数据时应该如何渲染和使用
  • 从零开始构建文本统计模型:字符级与多字符片段频率分析实践
  • java30
  • HCIP(BGP综合实验)
  • linux批量创建文件
  • RHEL7安装教程
  • 【QT】自定义QWidget标题栏,可拖拽(拖拽时窗体变为normal大小),可最小/大化、关闭(图文详情)
  • Spring AI之RAG入门
  • SpringBoot3.2新特性:JdbcClient
  • 模块化交互数字人系统:OpenAvatarChat,单台PC即可运行完整功能
  • 【Redis】大key对持久化的影响
  • 网站建设投资大概每年需要多少钱/云优化
  • 华为云做网站不能修改页面/网络营销方法有哪些?
  • 网站表单及商品列表详情模板/网站推广服务商
  • 高端网站设计简介/武汉疫情最新动态
  • JAVA网站开发ssm/企业邮箱如何申请注册
  • 网站出问题/郴州网站定制