|
| 1 | +/* |
| 2 | +풀이 |
| 3 | +- valid tree인지 판별하는 문제입니다 |
| 4 | + 주어진 input이 valid tree이려면, |
| 5 | + 1. cycle이 없어야 합니다 (cycle이 있는 경우: [[0, 1], [1, 2], [2, 0]]) |
| 6 | + 2. 모든 node가 연결되어 있어야 합니다 (모든 node가 연결되지 않은 경우: [[0, 1], [2, 3]]) |
| 7 | +- dfs 방식의 함수를 재귀 호출하여 풀이할 수 있습니다 |
| 8 | +Big O |
| 9 | +- N: n |
| 10 | +- E: 주어진 배열 edges의 크기 |
| 11 | +- Time complexity: O(N) |
| 12 | + - 모든 node를 최대 1번씩 탐색합니다 |
| 13 | +- Space complexity: O(E + N) |
| 14 | + - visited의 크기는 N에 비례하여 증가합니다 -> O(N) |
| 15 | + - adj의 크기는 E에 비례하여 증가합니다 -> O(E) |
| 16 | + - dfs의 재귀호출 스택 깊이는 최악의 경우 N까지 커질 수 있습니다 -> O(N) |
| 17 | +*/ |
| 18 | + |
| 19 | +func validTree(n int, edges [][]int) bool { |
| 20 | + // valid tree는 n-1개의 edge를 가질 수 밖에 없습validTree |
| 21 | + // 아래 판별식을 이용하면 유효하지 않은 input에 대해 상당한 연산을 줄일 수 있습니다 |
| 22 | + if len(edges) != n-1 { |
| 23 | + return false |
| 24 | + } |
| 25 | + // 주어진 2차원 배열 edges를 이용해 adjacency list를 생성합니다 |
| 26 | + adj := make([][]int, n) |
| 27 | + for _, edge := range edges { |
| 28 | + adj[edge[0]] = append(adj[edge[0]], edge[1]) |
| 29 | + adj[edge[1]] = append(adj[edge[1]], edge[0]) |
| 30 | + } |
| 31 | + // cycle이 있는지 여부를 판단하기 위해 visited라는 map을 생성합니다 (Go에서는 map으로 set 기능을 대신함) |
| 32 | + visited := make(map[int]bool) |
| 33 | + |
| 34 | + var dfs func(int, int) bool |
| 35 | + dfs = func(node int, parent int) bool { |
| 36 | + // cycle 발견시 false return |
| 37 | + if _, ok := visited[node]; ok { |
| 38 | + return false |
| 39 | + } |
| 40 | + visited[node] = true |
| 41 | + for _, next := range adj[node] { |
| 42 | + if next == parent { |
| 43 | + continue |
| 44 | + } |
| 45 | + if !dfs(next, node) { |
| 46 | + return false |
| 47 | + } |
| 48 | + } |
| 49 | + return true |
| 50 | + } |
| 51 | + // cycle 여부를 판단합니다 |
| 52 | + if !dfs(0, -1) { |
| 53 | + return false |
| 54 | + } |
| 55 | + // node가 모두 연결되어 있는지 여부를 판단합니다 |
| 56 | + return len(visited) == n |
| 57 | +} |
0 commit comments