잘못된 정보가 있다면, 꼭 댓글로 알려주세요(비로그인 익명도 가능).

여러분의 피드백이 저와 방문자 모두를 올바른 정보로 인도할 수 있습니다.

감사합니다. -현록

후원해주실 분은 여기로→

현록의 기록저장소

[Lv3] 가장 먼 노드 본문

Problem Solving/programmers

[Lv3] 가장 먼 노드

현록 2019. 4. 25. 00:52

https://programmers.co.kr/learn/challenges

 

프로그래밍 강의 | 프로그래머스

기초부터 차근차근, 직접 코드를 작성해 보세요.

programmers.co.kr

문제 설명

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
Comments

잘못된 정보가 있다면, 꼭 댓글로 알려주세요(비로그인 익명도 가능).

여러분의 피드백이 저와 방문자 모두를 올바른 정보로 인도할 수 있습니다.

감사합니다. -현록

후원해주실 분은 여기로→