LC 2603. 收集树中金币
https://leetcode.cn/problems/collect-coins-in-a-tree/
稍微有点难想到,看了 题解 之后才明白。
最开始我的想法非常直接,就是枚举每个节点,去判断”如果以这个节点为根,至少需要move到哪些节点才行“。 但是这种算法的时间复杂度就是O(n^2).
我也考虑过是否可以做换根DP,我看讨论区里面也给出了这个解法,但是稍微有点难理解。
最后题解中给出的拓扑排序的算法算是看懂了。
- 首先将coin=0的叶子节点不断地递归删除掉,这样留下来的叶子节点都是有coin的(拓扑排序)
- 然后从这些叶子节点出发,判断至少需要到达那些节点(假设是X),才能将这些叶子节点cover住
- 集合X中的节点肯定都是相连接并且没有回路的,走遍这些节点然后回来的长度就是 `2*(|X|-1)`
之前没有怎么写过无向图的拓扑排序,判断条件是 `ind[x]=1`. 然后在这种情况下面,可能ind[x]会变为负数,考虑0,1节点相连的情况。
然后在第二次遍历的时候,我们依然可以说使用 `ind[x]=1` 判断条件。
class Solution:
def collectTheCoins(self, coins: List[int], edges: List[List[int]]) -> int:
n = len(edges) + 1
adj = [[] for _ in range(n)]
ind = [0] * n
for x, y in edges:
adj[x].append(y)
adj[y].append(x)
ind[x] += 1
ind[y] += 1
# remove leaf node coin = 0
from collections import deque
q = deque()
for i in range(n):
if ind[i] == 1 and coins[i] == 0:
q.append(i)
while q:
x = q.popleft()
for y in adj[x]:
ind[y] -= 1
if ind[y] == 1 and coins[y] == 0:
q.append(y)
# walk from leaf node to mark depth.
q = deque()
depth = [0] * n
for i in range(n):
if ind[i] == 1 and coins[i]:
q.append(i)
depth[i] = 0
while q:
x = q.popleft()
for y in adj[x]:
ind[y] -= 1
# won't lead to coins = 0 leaf.
if ind[y] == 1:
depth[y] = depth[x] + 1
q.append(y)
edge = len([x for x in range(n) if depth[x] >= 2]) - 1
if edge < 0: return 0
ans = 2 * edge
return ans