leetcode(32)前缀和系列题目
303. 区域和检索 - 数组不可变
记录前i个元素的和,因此sum[left,right + 1]=pre[right + 1]-pre[left]
class NumArray:
def __init__(self, nums: List[int]):
self.pre_sum = [0]
for i in range(len(nums)):
self.pre_sum.append(self.pre_sum[i] + nums[i])
def sumRange(self, left: int, right: int) -> int:
return self.pre_sum[right + 1] - self.pre_sum[left]
# Your NumArray object will be instantiated and called as such:
# obj = NumArray(nums)
# param_1 = obj.sumRange(left,right)
1856. 子数组最小乘积的最大值
前缀和+单调栈
class Solution:
def maxSumMinProduct(self, nums: List[int]) -> int:
pre_sum = [0]
for i in range(len(nums)):
pre_sum.append(nums[i] + pre_sum[i])
res = 0
nums = [-inf] + nums + [-inf]
stack = []
for r, n in enumerate(nums):
while stack and nums[stack[-1]] > n:
i = stack.pop()
# print(nums[i])
# print(nums[stack[-1]:r])
cur = nums[i] * (pre_sum[r - 1] - pre_sum[stack[-1]]) # 注意r-1
res = max(res, cur)
stack.append(r)
return res % (10 ** 9 + 7)
238. 除自身以外数组的乘积
前缀积 * 后缀积
class Solution:
def productExceptSelf(self, nums: List[int]) -> List[int]:
n = len(nums)
pre = [1]
for i in range(n - 1):
pre.append(pre[i] * nums[i])
# print(pre)
tail = [1] * n
for j in range(n - 2, -1, -1):
tail[j] = tail[j + 1] * nums[j + 1]
# print(tail)
res = []
for i in range(n):
res.append(pre[i] * tail[i])
return res
1732. 找到最高海拔
自己的写法:
class Solution:
def largestAltitude(self, gain: List[int]) -> int:
gain = [0] + gain
res = gain[0]
cur = 0
for g in gain:
cur += g
res = max(res, cur)
return res
简洁写法:
class Solution:
def largestAltitude(self, gain: List[int]) -> int:
res = max(accumulate(gain,initial = 0))
return res
813. 最大平均值和的分组
dp[i][j] 表示 \(\textit{nums}\) 在区间 \([0, i-1]\) 被切分成 j 个子数组的最大平均值和
class Solution:
def largestSumOfAverages(self, nums: List[int], k: int) -> float:
pre_sum = list(accumulate(nums, initial = 0))
# print(pre_sum)
n = len(nums)
dp = [[0] * (k + 1) for _ in range(n + 1)]
for i in range(1, n + 1): # 前i个数全部分成1组
dp[i][1] = pre_sum[i] / i
for j in range(2, k + 1): # 分成j组
for i in range(j, n + 1): # 前i个数
for x in range(i): # 前x个数分成j-1组 + [x-i]这1组
dp[i][j] = max(dp[i][j], dp[x][j-1] + (pre_sum[i] - pre_sum[x]) / (i-x))
return dp[n][k]
1769. 移动所有球到每个盒子所需的最小操作数
分别计算前缀和和后缀和
class Solution:
def minOperations(self, boxes: str) -> List[int]:
n = len(boxes)
left, right = [0] * n, [0] * n
cnt = 0
for i in range(1, n):
if boxes[i - 1] == '1':
cnt += 1
left[i] = left[i - 1] + cnt
cnt = 0
for i in range(n-2, -1, -1):
if boxes[i + 1] == '1':
cnt += 1
right[i] = right[i + 1] + cnt
return [a + b for a, b in zip(left, right)]