记录了初步解题思路 以及本地实现代码;并不一定为最优 也希望大家能一起探讨 一起进步
目录
6/8 2161. 根据给定数字划分数组
按题意,结果数组要分成三段:
所有小于 pivot 的元素
所有等于 pivot 的元素
所有大于 pivot 的元素
并且每一段内部要保持原数组中的相对顺序,所以可直接一次遍历分类收集到三个列表
最后返回 less + equal + greater 即可
python
def pivotArray(nums, pivot):
"""
:type nums: List[int]
:type pivot: int
:rtype: List[int]
"""
less = []
equal = []
greater = []
for x in nums:
if x < pivot:
less.append(x)
elif x == pivot:
equal.append(x)
else:
greater.append(x)
return less + equal + greater
6/9 3689. 最大子数组总值 I
相同子数组可以被选择超过一次
即找最大的一个子数组即可
找到最大值 最小值 他们在的子数组值最大
python
def maxTotalValue(nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
return (max(nums)-min(nums))*k
6/10 3691. 最大子数组总值 II
稀疏表 + 最大堆,多路归并
固定左端点 l,子数组值 f_l® = max(numsl...r) - min(numsl...r)。
当 r 向右扩展时,区间最大值只会不降、最小值只会不升,
所以 f_l® 单调不减。
因此对每个 l 而言,按 r = n-1, n-2, ..., l 的顺序看,
对应值是一个"非增序列"。问题变成:从 n 个非增序列里取前 k 大元素求和。
用最大堆做多路归并:
每个 l 先把 (l, n-1) 入堆(即该序列当前最大值)
每次弹出全局最大 (l, r),把它计入答案
再把同一序列的下一个元素 (l, r-1) 入堆(若 r-1 >= l)
关键是快速求任意区间 max/min:用 Sparse Table 预处理
python
def maxTotalValue(nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
import heapq
n = len(nums)
if n == 0 or k == 0:
return 0
log2 = [0] * (n + 1)
for i in range(2, n + 1):
log2[i] = log2[i // 2] + 1
max_level = log2[n]
# st_max[j][i] 表示区间 [i, i + 2^j - 1] 的最大值
# st_min[j][i] 表示区间 [i, i + 2^j - 1] 的最小值
st_max = [nums[:]]
st_min = [nums[:]]
j = 1
while j <= max_level:
length = 1 << j
half = length >> 1
size = n - length + 1
prev_max = st_max[j - 1]
prev_min = st_min[j - 1]
cur_max = [0] * size
cur_min = [0] * size
for i in range(size):
left_max = prev_max[i]
right_max = prev_max[i + half]
cur_max[i] = left_max if left_max >= right_max else right_max
left_min = prev_min[i]
right_min = prev_min[i + half]
cur_min[i] = left_min if left_min <= right_min else right_min
st_max.append(cur_max)
st_min.append(cur_min)
j += 1
def range_value(l, r):
"""返回子数组 nums[l..r] 的值 = max - min。"""
p = log2[r - l + 1]
seg_len = 1 << p
max_val = st_max[p][l]
other_max = st_max[p][r - seg_len + 1]
if other_max > max_val:
max_val = other_max
min_val = st_min[p][l]
other_min = st_min[p][r - seg_len + 1]
if other_min < min_val:
min_val = other_min
return max_val - min_val
# 最大堆
heap = []
right = n - 1
for left in range(n):
heapq.heappush(heap, (-range_value(left, right), left, right))
ans = 0
for _ in range(k):
neg_val, left, right = heapq.heappop(heap)
ans -= neg_val
# 同一左端点序列的下一个候选 (left, right-1)
if right - 1 >= left:
nxt_r = right - 1
heapq.heappush(heap, (-range_value(left, nxt_r), left, nxt_r))
return ans
6/11 3558. 给边赋权值的方案数 I
只关心从根节点 1 到"某个最深节点 x"的那条路径,其他边可忽略。
设该路径有 d 条边(即最大深度为 d)。
每条边权只能取 1 或 2,路径总和奇偶性只由"取 1 的条数"决定:
加 1 会翻转奇偶
加 2 不改变奇偶
因此问题变成:长度为 d 的位置上,每个位置选 1/2,有多少种方案让总和为奇数?
等价于"选奇数个位置放 1",组合恒等式可得方案数为 2^(d-1)。
所以只需求树的最大深度 d,然后返回 pow(2, d-1, MOD)。
python
def assignEdgeWeights(edges):
"""
:type edges: List[List[int]]
:rtype: int
"""
from collections import deque
MOD = 10**9 + 7
n = len(edges) + 1
# 邻接表建树
g = [[] for _ in range(n + 1)]
for u, v in edges:
g[u].append(v)
g[v].append(u)
# BFS 求从根 1 出发的最大深度(按"边数"计)
q = deque([(1, 0, 0)]) # (node, parent, depth)
max_depth = 0
while q:
cur, parent, depth = q.popleft()
if depth > max_depth:
max_depth = depth
for nxt in g[cur]:
if nxt != parent:
q.append((nxt, cur, depth + 1))
# d >= 1(题目 n >= 2),返回 2^(d-1) % MOD
return pow(2, max_depth - 1, MOD)
6/12 3559. 给边赋权值的方案数 II
对单次查询 u, v,设路径边数为 d。
每条边可赋值 1 或 2,路径和奇偶性只取决于"有多少条边取 1":
加 1 会翻转奇偶
加 2 不改变奇偶
因此可行方案数 = 在 d 条边里选奇数条放 1 的方案数 = 2^(d-1)(d=0 时为 0)。
用 LCA(最近公共祖先)倍增预处理:
先 BFS 求每个点深度 depth 和其 2^j 级祖先 upjx
每次查询 O(log n) 求 lca(u, v)
距离 d = depthu + depthv - 2*depthlca
最终答案:
d == 0 -> 0
d > 0 -> pow(2, d-1, MOD)
python
def assignEdgeWeights(edges, queries):
"""
:type edges: List[List[int]]
:type queries: List[List[int]]
:rtype: List[int]
"""
from collections import deque
MOD = 10**9 + 7
n = len(edges) + 1
log = n.bit_length()
# 建图
g = [[] for _ in range(n + 1)]
for u, v in edges:
g[u].append(v)
g[v].append(u)
# up[j][x]: 节点 x 的 2^j 级祖先(0 表示不存在)
up = [[0] * (n + 1) for _ in range(log)]
depth = [0] * (n + 1)
# BFS 预处理 depth 和 up[0]
q = deque([1])
parent = [0] * (n + 1)
parent[1] = 0
while q:
x = q.popleft()
for y in g[x]:
if y == parent[x]:
continue
parent[y] = x
depth[y] = depth[x] + 1
up[0][y] = x
q.append(y)
# 倍增表
for j in range(1, log):
prev = up[j - 1]
cur = up[j]
for x in range(1, n + 1):
mid = prev[x]
cur[x] = prev[mid] if mid else 0
def lca(a, b):
if depth[a] < depth[b]:
a, b = b, a
# 先把 a 提升到与 b 同深度
diff = depth[a] - depth[b]
bit = 0
while diff:
if diff & 1:
a = up[bit][a]
diff >>= 1
bit += 1
if a == b:
return a
# 同时向上跳,找到 LCA 的下一层
for j in range(log - 1, -1, -1):
if up[j][a] != up[j][b]:
a = up[j][a]
b = up[j][b]
return up[0][a]
ans = []
for u, v in queries:
p = lca(u, v)
d = depth[u] + depth[v] - 2 * depth[p]
if d == 0:
ans.append(0)
else:
ans.append(pow(2, d - 1, MOD))
return ans
6/13
python
6/14
python