前缀和是一种重要的预处理,可以降低查询的时间复杂度。
面试题 04.12. 求和路径
给定一棵二叉树,其中每个节点都含有一个整数数值(该值或正或负)。设计一个算法,打印节点数值总和等于某个给定值的所有路径的数量。注意,路径不一定非得从二叉树的根节点或叶节点开始或结束,但是其方向必须向下(只能从父节点指向子节点方向)。
典型的前缀和解题。
面试题 04.12. 求和路径
class Solution:
def pathSum(self, root: TreeNode, sum: int) -> int:
# 统计前缀和的个数
d = {0:1}
def helper(t, cur):
if not t:
return 0
cur += t.val
r = 0
if cur-sum in d:
r += d[cur-sum]
d[cur] = d.get(cur, 0)+1
r += helper(t.left, cur)
r += helper(t.right, cur)
d[cur] -= 1
return r
return helper(root, 0)
面试题 17.05. 字母与数字
给定一个放有字母和数字的数组,找到最长的连续子数组,且包含的字母和数字的个数相同。返回该子数组,若存在多个最长子数组,返回左端点下标值最小的子数组。若不存在这样的数组,返回一个空数组。
class Solution:
def findLongestSubarray(self, array: List[str]) -> List[str]:
n = len(array)
cur = 0
d = {0: -1}
maxlength = 0
start = 0
for i in range(n):
if array[i].isdigit():
cur += 1 # 数字用1表示
else:
cur -= 1 # 字母用-1表示
if cur not in d:
d[cur] = i
else:
if maxlength < i-d[cur]:
maxlength = i-d[cur]
start = d[cur]+1
return array[start:maxlength+start]
303.区域和检索-数组不可变
303.区域和检索-数组不可变
给定一个整数数组 nums,处理以下类型的多个查询:
计算索引 left 和 right (包含 left 和 right)之间的 nums 元素的 和 ,其中 left <= right
实现 NumArray 类:
NumArray(int[] nums) 使用数组 nums 初始化对象
int sumRange(int i, int j) 返回数组 nums 中索引 left 和 right 之间的元素的 总和 ,包含 left 和 right 两点(也就是 nums[left] + nums[left + 1] + … + nums[right] )
class NumArray:
def __init__(self, nums: List[int]):
m = len(nums)
if m>0:
self.prefix = [0]*m
t = 0
for i in range(m):
t += nums[i]
self.prefix[i] = t
def sumRange(self, left: int, right: int) -> int:
if left >0:
ans = self.prefix[right]-self.prefix[left-1]
else:
ans = self.prefix[right]
return ans
304.二维区域和检索-矩阵不可变
304.二维区域和检索-矩阵不可变
给定一个二维矩阵 matrix,以下类型的多个请求:
计算其子矩形范围内元素的总和,该子矩阵的 左上角 为 (row1, col1) ,右下角 为 (row2, col2) 。
实现 NumMatrix 类:
NumMatrix(int[][] matrix) 给定整数矩阵 matrix 进行初始化
int sumRegion(int row1, int col1, int row2, int col2) 返回 左上角 (row1, col1) 、右下角 (row2, col2) 所描述的子矩阵的元素 总和 。
class NumMatrix:
def __init__(self, matrix: List[List[int]]):
self.m = len(matrix)
if self.m !=0:
self.n = len(matrix[0])
self.prefix = [[0]*self.n for _ in range(self.m)]
for i in range(self.m):
for j in range(self.n):
if i>0 and j>0:
self.prefix[i][j] = matrix[i][j] +self.prefix[i-1][j]+self.prefix[i][j-1]-self.prefix[i-1][j-1]
elif i > 0:
self.prefix[i][j] = matrix[i][j] +self.prefix[i-1][j]
elif j > 0:
self.prefix[i][j] = matrix[i][j] +self.prefix[i][j-1]
else:
self.prefix[i][j] = matrix[i][j]
def sumRegion(self, row1: int, col1: int, row2: int, col2: int) -> int:
if row1>0 and col1>0:
ans = self.prefix[row2][col2]-self.prefix[row2][col1-1]-self.prefix[row1-1][col2]+self.prefix[row1-1][col1-1]
elif row1>0:
ans = self.prefix[row2][col2]-self.prefix[row1-1][col2]
elif col1 > 0:
ans = self.prefix[row2][col2]-self.prefix[row2][col1-1]
else:
ans = self.prefix[row2][col2]
return ans
427. 建立四叉树
427. 建立四叉树
给你一个 n * n 矩阵 grid ,矩阵由若干 0 和 1 组成。请你用四叉树表示该矩阵 grid 。
你需要返回能表示矩阵 grid 的 四叉树 的根结点。
四叉树数据结构中,每个内部节点只有四个子节点。此外,每个节点都有两个属性:
val:储存叶子结点所代表的区域的值。1 对应 True,0 对应 False。注意,当 isLeaf 为 False 时,你可以把 True 或者 False 赋值给节点,两种值都会被判题机制 接受 。
isLeaf: 当这个节点是一个叶子结点时为 True,如果它有 4 个子节点则为 False 。
class Node {
public boolean val;
public boolean isLeaf;
public Node topLeft;
public Node topRight;
public Node bottomLeft;
public Node bottomRight;
}
class Solution:
def construct(self, grid: List[List[int]]) -> 'Node':
n = len(grid)
prefix = [[0]*n for _ in range(n)]
for i in range(n):
for j in range(n):
if i>0 and j>0:
prefix[i][j] = grid[i][j] +prefix[i-1][j]+prefix[i][j-1]-prefix[i-1][j-1]
elif i > 0:
prefix[i][j] = grid[i][j] +prefix[i-1][j]
elif j > 0:
prefix[i][j] = grid[i][j] +prefix[i][j-1]
else:
prefix[i][j] = grid[i][j]
def helper(x1,y1,x2,y2):
if x2-x1==0:
return Node(grid[x1][y1], True, None, None, None, None)
a = x2-x1
# 计算和
if x1>0 and y1>0:
ans = prefix[x2][y2]-prefix[x2][y1-1]-prefix[x1-1][y2]+prefix[x1-1][y1-1]
elif x1>0:
ans = prefix[x2][y2]-prefix[x1-1][y2]
elif y1>0:
ans = prefix[x2][y2]-prefix[x2][y1-1]
else:
ans = prefix[x2][y2]
if ans==0 or ans == (a+1)*(a+1)*1:
return Node(grid[x1][y1], True, None, None, None, None)
else:
a = a//2
return Node(0, False, helper(x1,y1,x1+a,y1+a), helper(x1,y1+a+1,x1+a,y2), helper(x1+a+1,y1,x2,y1+a), helper(x1+a+1,y1+a+1,x2,y2))
return helper(0,0, n-1, n-1)
918. 环形子数组的最大和
918. 环形子数组的最大和
这道题目是很好的一道题目。
给定一个长度为 n 的环形整数数组 nums ,返回 nums 的非空 子数组 的最大可能和 。
环形数组 意味着数组的末端将会与开头相连呈环状。形式上, nums[i] 的下一个元素是 nums[(i + 1) % n] , nums[i] 的前一个元素是 nums[(i - 1 + n) % n] 。
子数组 最多只能包含固定缓冲区 nums 中的每个元素一次。形式上,对于子数组 nums[i], nums[i + 1], …, nums[j] ,不存在 i <= k1, k2 <= j 其中 k1 % n == k2 % n 。
class Solution:
def maxSubarraySumCircular(self, nums: List[int]) -> int:
n = len(nums)
# 1.连续的
# 2.两部分,计算前缀和和后缀和
pres = [nums[0]]
pre,ans,pp,mpp = nums[0],nums[0],nums[0],nums[0]
for i in range(1,n):
pre = max(pre+nums[i], nums[i])
ans = max(pre, ans)
pp += nums[i]
mpp = max(pp, mpp)
pres.append(mpp)
t = 0
for i in range(n-1, 0, -1):
t += nums[i]
ans = max(ans, t+pres[i-1])
return ans
class Solution:
def maxSubarraySumCircular(self, nums: List[int]) -> int:
n = len(nums)
# 1.连续的
# 2.两部分,计算前缀和和后缀和 == sum - 最小连续子数组和
pre,ans,ssum,mpre,mmin = nums[0],nums[0],nums[0],nums[0],nums[0]
for i in range(1,n):
pre = max(pre+nums[i], nums[i])
ans = max(pre, ans)
mpre = min(mpre+nums[i], nums[i])
mmin = min(mpre, mmin)
ssum += nums[i]
ans = max(ans, ssum-mmin) if ssum != mmin else ans
return ans
class Solution:
def maxSubarraySumCircular(self, nums: List[int]) -> int:
n = len(nums)
# nums + nums 转化为长度小于等于n的最大连续子数组
# 使用前缀数组 +
prefix = []
t = 0
for i in range(n+n):
t += nums[i%n]
prefix.append(t)
ans = nums[0]
dq = deque()
for i in range(n*2):
if not dq:
dq.append(i)
else:
while dq and i-dq[0] > n:
dq.popleft()
ans = max(ans, prefix[i]-prefix[dq[0]])
while dq and prefix[i] <= prefix[dq[-1]]:
dq.pop()
dq.append(i)
return ans
1801

被折叠的 条评论
为什么被折叠?



