跳到主要内容

2603.收集树中金币

链接:2603.收集树中金币
难度:Hard
标签:树、图、拓扑排序、数组
简介:你需要收集树中所有的金币,并且回到出发节点,请你返回最少经过的边数。

题解 1 - cpp

  • 编辑时间:2023-03-26
  • 执行用时:632ms
  • 内存消耗:206.8MB
  • 编程语言:cpp
  • 解法介绍:先删除所有没有金币的叶子节点,再遍历两次,删除有金币的叶子节点,剩下的节点就是所有需要遍历的节点。
class Solution {
public:
int collectTheCoins(vector<int>& coins, vector<vector<int>>& edges) {
int n = coins.size();
vector<vector<int>> list(n);
vector<int> cnts(n, 0);
for (auto &edge : edges) {
list[edge[0]].push_back(edge[1]);
list[edge[1]].push_back(edge[0]);
cnts[edge[0]] += 1;
cnts[edge[1]] += 1;
}
int cur_edges = n - 1;
queue<int> q;
// 第一次刪除所有的无金币叶子节点
for (int i = 0; i < n; i++) {
if (cnts[i] == 1 && coins[i] == 0) q.push(i);
}
while (q.size()) {
int idx = q.front();
q.pop();
cur_edges -= 1;
for (auto &next : list[idx]) {
cnts[next] -= 1;
if (cnts[next] == 1 && coins[next] == 0) q.push(next);
}
}
// 第二次寻找所有的叶子金币节点
for (int i = 0; i < n; i++) {
if (cnts[i] == 1 && coins[i] == 1) q.push(i);
}
cur_edges -= q.size();
while (q.size()) {
int idx = q.front();
q.pop();
for (auto &next : list[idx]) {
cnts[next] -= 1;
if (cnts[next] == 1) {
cnts[next] -= 1;
cur_edges -= 1;
}
}
}
return max(cur_edges * 2, 0);
}
};

题解 2 - python

  • 编辑时间:2023-03-26
  • 执行用时:256ms
  • 内存消耗:27.6MB
  • 编程语言:python
  • 解法介绍:同上。
class Solution:
def collectTheCoins(self, coins: List[int], edges: List[List[int]]) -> int:
n = len(coins)
l = [[] for _ in range(n)]
cnts = [0] * n
for edge in edges:
l[edge[0]].append(edge[1])
l[edge[1]].append(edge[0])
cnts[edge[0]] += 1
cnts[edge[1]] += 1
cur_edges = n - 1
q = deque()
for i in range(n):
if cnts[i] == 1 and coins[i] == 0:
q.append(i)
while len(q):
idx = q.popleft()
cur_edges -= 1
for ne in l[idx]:
cnts[ne] -= 1
if cnts[ne] == 1 and coins[ne] == 0:
q.append(ne)
for i in range(n):
if cnts[i] == 1 and coins[i] == 1:
q.append(i)
cur_edges -= len(q)
while len(q):
idx = q.popleft()
for ne in l[idx]:
cnts[ne] -= 1
if cnts[ne] == 1:
cnts[ne] -= 1
cur_edges -= 1
return max(cur_edges * 2, 0)

题解 3 - rust

  • 编辑时间:2023-03-26
  • 执行用时:52ms
  • 内存消耗:5.2MB
  • 编程语言:rust
  • 解法介绍:同上。
impl Solution {
pub fn collect_the_coins(coins: Vec<i32>, edges: Vec<Vec<i32>>) -> i32 {
let n = coins.len();
let mut list = vec![vec![]; n];
let mut cnts = vec![0; n];
for edge in edges {
list[edge[0] as usize].push(edge[1]);
list[edge[1] as usize].push(edge[0]);
cnts[edge[0] as usize] += 1;
cnts[edge[1] as usize] += 1;
}
let mut cur_edges = n - 1;
let mut q = std::collections::VecDeque::<usize>::new();
for i in 0..n {
if cnts[i] == 1 && coins[i] == 0 {
q.push_back(i);
}
}
while !q.is_empty() {
let idx = q.pop_front().unwrap();
cur_edges -= 1;
for next in list[idx].iter() {
let next = *next as usize;
cnts[next] -= 1;
if cnts[next] == 1 && coins[next] == 0 {
q.push_back(next)
}
}
}
for i in 0..n {
if cnts[i] == 1 && coins[i] == 1 {
q.push_back(i);
}
}
cur_edges -= q.len();
while !q.is_empty() {
let idx = q.pop_front().unwrap();
for next in list[idx].iter() {
let next = *next as usize;
cnts[next] -= 1;
if cnts[next] == 1 {
cnts[next] -= 1;
cur_edges -= 1;
}
}
}
0.max(2 * cur_edges as i32)
}
}

题解 4 - python

  • 编辑时间:2023-09-21
  • 执行用时:3812ms
  • 内存消耗:28.9MB
  • 编程语言:python
  • 解法介绍:同上。
class Solution:
def collectTheCoins(self, coins: List[int], edges: List[List[int]]) -> int:
n = len(edges) + 1
nodes: List[List[int]] = [[] for _ in range(n)]
for [n1, n2] in edges:
nodes[n1].append(n2)
nodes[n2].append(n1)
egde_sum = n - 1
# 把叶子没金币的删掉
q = deque(i for i in range(n) if len(nodes[i]) == 1 and coins[i] == 0)
while q:
cur = q.pop()
for idx in nodes[cur]:
egde_sum -= 1
nodes[idx].remove(cur)
if len(nodes[idx]) == 1 and coins[idx] == 0:
q.append(idx)
# 遍历所有叶子有金币的
q = deque(i for i in range(n) if len(nodes[i]) == 1 and coins[i] == 1)
while q:
cur = q.pop()
egde_sum -= 1
for idx in nodes[cur]:
nodes[idx].remove(cur)
# 如果他只剩一条边,那就也可以不遍历他
if len(nodes[idx]) == 1:
egde_sum -= 1
return max(egde_sum * 2, 0)