잘못된 정보가 있다면, 꼭 댓글로 알려주세요(비로그인 익명도 가능).
여러분의 피드백이 저와 방문자 모두를 올바른 정보로 인도할 수 있습니다.
감사합니다. -현록
현록의 기록저장소
[Lv3] 가장 먼 노드 본문
https://programmers.co.kr/learn/challenges
문제 설명
n개의 노드가 있는 그래프가 있습니다. 각 노드는 1부터 n까지 번호가 적혀있습니다. 1번 노드에서 가장 멀리 떨어진 노드의 갯수를 구하려고 합니다. 가장 멀리 떨어진 노드란 최단경로로 이동했을 때 간선의 개수가 가장 많은 노드들을 의미합니다.
노드의 개수 n, 간선에 대한 정보가 담긴 2차원 배열 edge가 매개변수로 주어질 때, 1번 노드로부터 가장 멀리 떨어진 노드가 몇 개인지를 return 하도록 solution 함수를 작성해주세요.
제한사항
- 노드의 개수 n은 2 이상 20,000 이하입니다.
- 간선은 양방향이며 총 1개 이상 50,000개 이하의 간선이 있습니다.
- edge 배열 각 행 [a, b]는 a번 노드와 b번 노드 사이에 간선이 있다는 의미입니다.
입출력 예
n | edge | return |
6 | [[3, 6], [4, 3], [3, 2], [1, 3], [1, 2], [2, 4], [5, 2]] | 3 |
입출력 예 설명
예제의 그래프를 표현하면 아래 그림과 같고, 1번 노드에서 가장 멀리 떨어진 노드는 4,5,6번 노드입니다.
노드 간에 이어질 수 있는 노드의 수 제한이 없습니다.
새로 가지 못하는 노드도 있고, 1~무한대로 뻗어나갈 수 있습니다.
인접노드의 숫자를 정할 수 없으니, 가변저장소를 쓸텐데, 저는 HashSet으로 했습니다.
class Node {
int no;
HashSet<Node> other;
Node(int no) {
this.no= no;
other = new HashSet<>();
}
}
ArrayList<Node> list = new ArrayList<>();
for(int i=1;i<=n;i++) list.add(new Node(i));
for(int[] arr:edge) {
int node1 = arr[0];
int node2 = arr[1];
list.get(node1-1).other.add(list.get(node2-1));
list.get(node2-1).other.add(list.get(node1-1));
}
int[] shortest = new int[n];
ArrayList<Node>로 순서로 get할 수 있게 노드들을 만들어서 넣어주고,
주어진 배열 edge를 돌면서, 서로간의 HashSet<Node>에 연결가능한 다음 노드들을 넣어줍니다.
이제 int[] shortest에 최단거리를 기록해나갈겁니다.
public void set(int[] shortest, Node now, int val) {
LinkedList<Node> list = null;
for(Node other:now.other) {
if(other.no!=1) {
if(shortest[other.no-1]==0) {
if(list==null) list = new LinkedList<>();
shortest[other.no-1] = val+1;
list.add(other);
} else if(val+1<shortest[other.no-1]) {
if(list==null) list = new LinkedList<>();
shortest[other.no-1] = val+1;
list.add(other);
}
}
}
if(list!=null) {
for(Node other:list) set(shortest, other, val+1);
}
}
원래는 DFS로 문제를 풀려고 했습니다.
최대한 쓸데없이 호출되지 않도록 0이거나(처음이거나) 이번 루트가 더 짧거나일 때만 list에 넣었다가
(이번 노드에 인접노드는 동일한 값을 매겨주고 난 다음에 번져가기 위해 list를 두어 나중에 따로 호출)
했는데도 한 케이스에서는 StackOverFlow로 추정되는 런타임 오류가 발생했습니다.
그래서 그냥 스택을 이용해 차근차근 풀어나가도록 했습니다.
Stack<Node> toDo = new Stack<>();
toDo.push(list.get(0));
int val = 0;
while(!toDo.isEmpty()) {
Node now = toDo.pop();
val = shortest[now.no-1];
val++;
for(Node next:now.other) {
if(next.no!=1) {
if(shortest[next.no-1]==0||val<shortest[next.no-1]) {
shortest[next.no-1] = val;
toDo.push(next);
}
}
}
}
스택에 먼저 1번 노드를 넣어줍니다.
val은 이번 노드의 최단거리입니다. 여기서 1 증가한 게 다음 노드의 최단거리가 되겠죠.
이번 노드의 HashSet에서 연결된 노드들 중
처음이거나, 이번 루트가 더 짧을 경우에 최단거리로 판정하고 val을 매겨준 뒤, 스택에 넣습니다.
이렇게 스택에서 차곡차곡 빼면서 최단거리로 더 번질 수 없으면 스택에 쌓이지 못하면서 루프가 끝나겠죠.
int max = 0;
for(int i=1;i<n;i++) if(shortest[i]>max) max=shortest[i];
int answer = 0;
for(int i=1;i<n;i++) if(shortest[i]==max) answer++;
return answer;
그 다음은 그냥 최고로 먼 거리를 구해서, 그 거리에 해당하는 노드의 수를 세서 반환해줍니다.
노드간 연결될 수 있는 수가 제한이 없어서 가변저장소를 사용했고,
그래서 여러 갈래로 번지느라 이미 값이 있어도 더 최단거리인 루트가 생기기도 하는 점 기억.
'Problem Solving > programmers' 카테고리의 다른 글
[Lv4] 지형 편집 (2) | 2019.04.30 |
---|---|
[Lv3] 보행자 천국 (0) | 2019.04.25 |
[Lv5] 블록 게임 (0) | 2019.04.24 |
[Lv5] 매칭 점수 (0) | 2019.04.24 |
[Lv5] 길 찾기 게임 (0) | 2019.04.24 |
잘못된 정보가 있다면, 꼭 댓글로 알려주세요(비로그인 익명도 가능).
여러분의 피드백이 저와 방문자 모두를 올바른 정보로 인도할 수 있습니다.
감사합니다. -현록