记录了初步解题思路 以及本地实现代码;并不一定为最优 也希望大家能一起探讨 一起进步
目录
-
-
- [7/6 1288. 删除被覆盖区间](#7/6 1288. 删除被覆盖区间)
- [7/7 3754. 连接非零数字并乘以其数字和 I](#7/7 3754. 连接非零数字并乘以其数字和 I)
- [7/8 3756. 连接非零数字并乘以其数字和 II](#7/8 3756. 连接非零数字并乘以其数字和 II)
- [7/9 3532. 针对图的路径存在性查询 I](#7/9 3532. 针对图的路径存在性查询 I)
- [7/10 3534. 针对图的路径存在性查询 II](#7/10 3534. 针对图的路径存在性查询 II)
- [7/11 2685. 统计完全连通分量的数量](#7/11 2685. 统计完全连通分量的数量)
- 7/12
-
7/6 1288. 删除被覆盖区间
先按区间左端点升序排序;如果左端点相同,按右端点降序排序。
遍历排序后的区间,维护当前看到的最大右端点 max_r:
若当前区间右端点 r <= max_r,说明它被前面的某个区间覆盖,跳过。
否则它没有被覆盖,答案加 1,并更新 max_r = r。
python
def removeCoveredIntervals(intervals):
"""
:type intervals: List[List[int]]
:rtype: int
"""
intervals.sort(key=lambda x: (x[0], -x[1]))
ans = 0
max_r = -1
for _, r in intervals:
if r <= max_r:
continue
ans += 1
max_r = r
return ans
7/7 3754. 连接非零数字并乘以其数字和 I
遍历数字的每一位,将非零数字连接起来,并乘以其数字和
python
def sumAndMultiply(n):
"""
:type n: int
:rtype: int
"""
s = 0
num = 0
d = 0
while n:
digit = n % 10
s+=digit
if digit > 0:
num = num+ digit*(10**d)
d+=1
n = n // 10
return num*s
7/8 3756. 连接非零数字并乘以其数字和 II
预处理三个前缀数组:
sum_di:前 i 个字符中所有数字之和
cnt_n0i:前 i 个字符中非零数字个数
pi:前 i 个字符中非零数字拼接后的值(对 MOD 取模)
并预处理 pow10k = 10^k % MOD。
对于查询 l, r:
n0 = cnt_n0r+1 - cnt_n0l,即子串非零位个数
sd = sum_dr+1 - sum_dl,即子串非零位的数字和
由pr+1 = pl * 10^n0 + x
x = pr+1 - pl * 10^n0
取模后即为子串拼接值
返回 x * sd % MOD
python
def sumAndMultiply(s, queries):
"""
:type s: str
:type queries: List[List[int]]
:rtype: List[int]
"""
MOD = 10**9 + 7
n = len(s)
sum_d = [0] * (n + 1)
cnt_n0 = [0] * (n + 1)
p = [0] * (n + 1)
pow10 = [1] * (n + 1)
for i, ch in enumerate(s):
d = ord(ch) - ord('0')
sum_d[i + 1] = sum_d[i] + d
pow10[i + 1] = (pow10[i] * 10) % MOD
if d == 0:
cnt_n0[i + 1] = cnt_n0[i]
p[i + 1] = p[i]
else:
cnt_n0[i + 1] = cnt_n0[i] + 1
p[i + 1] = (p[i] * 10 + d) % MOD
ans = []
for l, r in queries:
n0 = cnt_n0[r + 1] - cnt_n0[l]
sd = sum_d[r + 1] - sum_d[l]
x = (p[r + 1] - (p[l] * pow10[n0]) % MOD + MOD) % MOD
ans.append((x * sd) % MOD)
return ans
7/9 3532. 针对图的路径存在性查询 I
因为 nums 已经非递减排序,若两个相邻点 i-1 和 i 满足
numsi - numsi-1 <= maxDiff,
则这两个点直接有边,可以连在同一连通块里。
进一步可知:同一连通块在下标上一定是连续的一段。
所以只需线性扫描一次 nums,给每个下标分配一个"连通块编号":
从左到右遍历 i=1...n-1。
若 numsi - numsi-1 > maxDiff,说明连通块断开,编号 +1。
compi 记录当前编号。
回答查询 u, v 时,只要判断 compu == compv 即可。
python
def pathExistenceQueries(n, nums, maxDiff, queries):
"""
:type n: int
:type nums: List[int]
:type maxDiff: int
:type queries: List[List[int]]
:rtype: List[bool]
"""
comp = [0] * n
cid = 0
for i in range(1, n):
if nums[i] - nums[i - 1] > maxDiff:
cid += 1
comp[i] = cid
return [comp[u] == comp[v] for u, v in queries]
7/10 3534. 针对图的路径存在性查询 II
边的定义只和数值差有关,与原下标无关。
把点按 nums 值排序后,设排序后位置为 0...n-1。
若 i < j 且 valj - vali <= maxDiff,则 i 与 j 直接相连。
对固定 i,一步能到达的右侧点是一个连续区间,记其最远端为 reachi。
reach 可以用双指针在线性时间求出。
查询最短路时,先把原节点下标映射到排序后位置 s,t(设 s <= t):
若 s == t,答案是 0。
问题变成:从 s 到 t,最少几步"每步最多跳到 reachcur"。
这是典型最小跳跃问题,可用倍增优化。
倍增定义:
upki 表示从 i 出发走 2^k 步后,最远能到达的位置。
转移:
up0i = reachi
upki = upk-1 up\[k-1i ]
对每个查询贪心地从大到小尝试 2^k:
若 upkcur < t,就先跳这 2^k 步并累加答案。
最后再跳一步即可到达/越过 t。
如果从 s 出发任意步都到不了 t,返回 -1。
python
def pathExistenceQueries(n, nums, maxDiff, queries):
"""
:type n: int
:type nums: List[int]
:type maxDiff: int
:type queries: List[List[int]]
:rtype: List[int]
"""
pairs = sorted((v, i) for i, v in enumerate(nums))
vals = [v for v, _ in pairs]
pos = [0] * n
for idx, (_, orig_i) in enumerate(pairs):
pos[orig_i] = idx
reach = [0] * n
r = 0
for i in range(n):
if r < i:
r = i
while r + 1 < n and vals[r + 1] - vals[i] <= maxDiff:
r += 1
reach[i] = r
comp = [0] * n
cid = 0
for i in range(1, n):
if vals[i] - vals[i - 1] > maxDiff:
cid += 1
comp[i] = cid
max_log = n.bit_length()
up = [[0] * n for _ in range(max_log)]
up[0] = reach[:]
for k in range(1, max_log):
prev = up[k - 1]
cur = up[k]
for i in range(n):
cur[i] = prev[prev[i]]
def min_steps(a, b):
s = pos[a]
t = pos[b]
if s > t:
s, t = t, s
if s == t:
return 0
if comp[s] != comp[t]:
return -1
ans = 0
cur = s
for k in range(max_log - 1, -1, -1):
nxt = up[k][cur]
if nxt < t:
ans += 1 << k
cur = nxt
return ans + 1
return [min_steps(u, v) for u, v in queries]
7/11 2685. 统计完全连通分量的数量
先把图建成邻接表,然后遍历每个未访问节点,用 DFS/BFS 找到一个连通分量。
设该分量有 k 个点。
一个包含 k 个点的完全图,边数应为 k*(k-1)/2。
因此在遍历分量时统计该分量所有点的度数之和 deg_sum,
则分量实际边数为 deg_sum/2(无向边被统计了两次)。
若 deg_sum/2 == k*(k-1)/2,说明该分量是完全连通分量,答案加一。
python
def countCompleteComponents(n, edges):
"""
:type n: int
:type edges: List[List[int]]
:rtype: int
"""
g = [[] for _ in range(n)]
for u, v in edges:
g[u].append(v)
g[v].append(u)
vis = [False] * n
ans = 0
for i in range(n):
if vis[i]:
continue
stack = [i]
vis[i] = True
nodes = 0
deg_sum = 0
while stack:
u = stack.pop()
nodes += 1
deg_sum += len(g[u])
for v in g[u]:
if not vis[v]:
vis[v] = True
stack.append(v)
if deg_sum // 2 == nodes * (nodes - 1) // 2:
ans += 1
return ans
7/12
python