树
图
拓扑排序
数组
题目描述
给你一个 n
个节点的无向无根树,节点编号从 0
到 n - 1
。给你整数 n
和一个长度为 n - 1
的二维整数数组 edges
,其中 edges[i] = [ai , bi ]
表示树中节点 ai
和 bi
之间有一条边。再给你一个长度为 n
的数组 coins
,其中 coins[i]
可能为 0
也可能为 1
,1
表示节点 i
处有一个金币。
一开始,你需要选择树中任意一个节点出发。你可以执行下述操作任意次:
收集距离当前节点距离为 2
以内的所有金币,或者
移动到树中一个相邻节点。
你需要收集树中所有的金币,并且回到出发节点,请你返回最少经过的边数。
如果你多次经过一条边,每一次经过都会给答案加一。
示例 1:
输入: coins = [1,0,0,0,0,1], edges = [[0,1],[1,2],[2,3],[3,4],[4,5]]
输出: 2
解释: 从节点 2 出发,收集节点 0 处的金币,移动到节点 3 ,收集节点 5 处的金币,然后移动回节点 2 。
示例 2:
输入: coins = [0,0,0,1,1,0,0,1], edges = [[0,1],[0,2],[1,3],[1,4],[2,5],[5,6],[5,7]]
输出: 2
解释: 从节点 0 出发,收集节点 4 和 3 处的金币,移动到节点 2 处,收集节点 7 处的金币,移动回节点 0 。
提示:
n == coins.length
1 <= n <= 3 * 104
0 <= coins[i] <= 1
edges.length == n - 1
edges[i].length == 2
0 <= ai , bi < n
ai != bi
edges
表示一棵合法的树。
解法
方法一:拓扑排序
我们先将 $edges$ 中的边转换成邻接表 $g$,其中 $g[i]$ 表示节点 $i$ 的所有邻接节点,用集合表示。
接下来我们遍历所有节点,找到 $coins[i]=0$ 且 $g[i]$ 中只有一个节点的节点(也即是金币为 $0$ 的叶子节点),将其加入队列 $q$ 中。
然后我们不断地从队列中取出节点,将其从邻接表中删除,然后判断其邻接节点是否满足 $coins[j]=0$ 且 $g[j]$ 中只有一个节点的条件,如果满足则将其加入队列 $q$ 中。循环,直至队列为空。
经过上述操作后,我们得到了一棵新的树,且树的叶子节点都是金币为 $1$ 的节点。
然后,我们再删除剩下的两层叶子节点,最终得到的是一棵所有节点都需要被访问的节点,我们只需要统计其边数,乘上 $2$,即为答案。
时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 为节点数。
相似题目:
Python3 Java C++ Go TypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 class Solution :
def collectTheCoins ( self , coins : List [ int ], edges : List [ List [ int ]]) -> int :
g = defaultdict ( set )
for a , b in edges :
g [ a ] . add ( b )
g [ b ] . add ( a )
n = len ( coins )
q = deque ( i for i in range ( n ) if len ( g [ i ]) == 1 and coins [ i ] == 0 )
while q :
i = q . popleft ()
for j in g [ i ]:
g [ j ] . remove ( i )
if coins [ j ] == 0 and len ( g [ j ]) == 1 :
q . append ( j )
g [ i ] . clear ()
for k in range ( 2 ):
q = [ i for i in range ( n ) if len ( g [ i ]) == 1 ]
for i in q :
for j in g [ i ]:
g [ j ] . remove ( i )
g [ i ] . clear ()
return sum ( len ( g [ a ]) > 0 and len ( g [ b ]) > 0 for a , b in edges ) * 2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 class Solution {
public int collectTheCoins ( int [] coins , int [][] edges ) {
int n = coins . length ;
Set < Integer >[] g = new Set [ n ] ;
Arrays . setAll ( g , k -> new HashSet <> ());
for ( var e : edges ) {
int a = e [ 0 ] , b = e [ 1 ] ;
g [ a ] . add ( b );
g [ b ] . add ( a );
}
Deque < Integer > q = new ArrayDeque <> ();
for ( int i = 0 ; i < n ; ++ i ) {
if ( coins [ i ] == 0 && g [ i ] . size () == 1 ) {
q . offer ( i );
}
}
while ( ! q . isEmpty ()) {
int i = q . poll ();
for ( int j : g [ i ] ) {
g [ j ] . remove ( i );
if ( coins [ j ] == 0 && g [ j ] . size () == 1 ) {
q . offer ( j );
}
}
g [ i ] . clear ();
}
q . clear ();
for ( int k = 0 ; k < 2 ; ++ k ) {
for ( int i = 0 ; i < n ; ++ i ) {
if ( g [ i ] . size () == 1 ) {
q . offer ( i );
}
}
for ( int i : q ) {
for ( int j : g [ i ] ) {
g [ j ] . remove ( i );
}
g [ i ] . clear ();
}
}
int ans = 0 ;
for ( var e : edges ) {
int a = e [ 0 ] , b = e [ 1 ] ;
if ( g [ a ] . size () > 0 && g [ b ] . size () > 0 ) {
ans += 2 ;
}
}
return ans ;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51 class Solution {
public :
int collectTheCoins ( vector < int >& coins , vector < vector < int >>& edges ) {
int n = coins . size ();
unordered_set < int > g [ n ];
for ( auto & e : edges ) {
int a = e [ 0 ], b = e [ 1 ];
g [ a ]. insert ( b );
g [ b ]. insert ( a );
}
queue < int > q ;
for ( int i = 0 ; i < n ; ++ i ) {
if ( coins [ i ] == 0 && g [ i ]. size () == 1 ) {
q . push ( i );
}
}
while ( ! q . empty ()) {
int i = q . front ();
q . pop ();
for ( int j : g [ i ]) {
g [ j ]. erase ( i );
if ( coins [ j ] == 0 && g [ j ]. size () == 1 ) {
q . push ( j );
}
}
g [ i ]. clear ();
}
for ( int k = 0 ; k < 2 ; ++ k ) {
vector < int > q ;
for ( int i = 0 ; i < n ; ++ i ) {
if ( g [ i ]. size () == 1 ) {
q . push_back ( i );
}
}
for ( int i : q ) {
for ( int j : g [ i ]) {
g [ j ]. erase ( i );
}
g [ i ]. clear ();
}
}
int ans = 0 ;
for ( auto & e : edges ) {
int a = e [ 0 ], b = e [ 1 ];
if ( g [ a ]. size () && g [ b ]. size ()) {
ans += 2 ;
}
}
return ans ;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51 func collectTheCoins ( coins [] int , edges [][] int ) int {
n := len ( coins )
g := make ([] map [ int ] bool , n )
for i := range g {
g [ i ] = map [ int ] bool {}
}
for _ , e := range edges {
a , b := e [ 0 ], e [ 1 ]
g [ a ][ b ] = true
g [ b ][ a ] = true
}
q := [] int {}
for i , c := range coins {
if c == 0 && len ( g [ i ]) == 1 {
q = append ( q , i )
}
}
for len ( q ) > 0 {
i := q [ 0 ]
q = q [ 1 :]
for j := range g [ i ] {
delete ( g [ j ], i )
if coins [ j ] == 0 && len ( g [ j ]) == 1 {
q = append ( q , j )
}
}
g [ i ] = map [ int ] bool {}
}
for k := 0 ; k < 2 ; k ++ {
q := [] int {}
for i := range coins {
if len ( g [ i ]) == 1 {
q = append ( q , i )
}
}
for _ , i := range q {
for j := range g [ i ] {
delete ( g [ j ], i )
}
g [ i ] = map [ int ] bool {}
}
}
ans := 0
for _ , e := range edges {
a , b := e [ 0 ], e [ 1 ]
if len ( g [ a ]) > 0 && len ( g [ b ]) > 0 {
ans += 2
}
}
return ans
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 function collectTheCoins ( coins : number [], edges : number [][]) : number {
const n = coins . length ;
const g : Set < number > [] = new Array ( n ). fill ( 0 ). map (() => new Set < number > ());
for ( const [ a , b ] of edges ) {
g [ a ]. add ( b );
g [ b ]. add ( a );
}
let q : number [] = [];
for ( let i = 0 ; i < n ; ++ i ) {
if ( coins [ i ] === 0 && g [ i ]. size === 1 ) {
q . push ( i );
}
}
while ( q . length ) {
const i = q . pop () ! ;
for ( const j of g [ i ]) {
g [ j ]. delete ( i );
if ( coins [ j ] === 0 && g [ j ]. size === 1 ) {
q . push ( j );
}
}
g [ i ]. clear ();
}
q = [];
for ( let k = 0 ; k < 2 ; ++ k ) {
for ( let i = 0 ; i < n ; ++ i ) {
if ( g [ i ]. size === 1 ) {
q . push ( i );
}
}
for ( const i of q ) {
for ( const j of g [ i ]) {
g [ j ]. delete ( i );
}
g [ i ]. clear ();
}
}
let ans = 0 ;
for ( const [ a , b ] of edges ) {
if ( g [ a ]. size > 0 && g [ b ]. size > 0 ) {
ans += 2 ;
}
}
return ans ;
}
GitHub