아래 프로그래머스 문제를 풀다가 발견한 문제이다.
대충 나는 kruskal 알고리즘을 사용하였고, union find 부분의 함수를 구현하고 있었다. 그런데 분명 TC도 다 맞고 로직 상의 문제는 없었을 코드가 계속 정확도 50점이 나왔다. 문제가 될 부분이 union find 밖에 없었기 때문에 수정하기 위해 IDE로 옮겼더니 인텔리제이가 힌트를 줬다 ^^;
// 문제에서 vertex의 번호가 0~N 범위 밖일 수 있기 때문에 parent 정보를 HashMap으로 만들어 저장했다.
// key: vertex, value: parent vertex
HashMap<Integer, Integer> parent = new HashMap<>();
내가 find()의 return에 map.put()을 넣었던 이유는
- 노드 v의 부모를 수정하면서 재귀를 타고 싶었고
- map.put()가 put이 적용된 다음의 value를 리턴한다고 생각했기 때문이다.
그래서 Unboxing of 'map.put(key, value)' may produce 'NullPointerException' 워닝이 떴을 때도 이게 왜 뜨지?? 했었다. 그냥 unboxing 과정에서 발생할 수 있는 문제 중 하나인가, 하고 넘어갔는데 내가 map.put()의 반환 값을 잘못 알고 있었다.
map.put()의 리턴 값은 key에 매핑된 '이전' value 이다. 키에 대한 매핑이 없거나 null과 매핑되었던 경우, null이 반환된다. 때문에 인텔리제이는 계속 NullPointerException가 발생할 수 있다고 알려줬던 것이다...
이 문제가 계속 틀렸던 것도 새로 갱신된 parent가 아니라 갱신되기 이전의 parent 값을 반환하였기 때문에 문제가 된 것 같다. 그래서 map.put() 리턴값을 활용하지 않고 아래처럼 작성했더니 통과할 수 있었다.
private int find(int v) {
if(v == parent.get(v)) return v;
int p = find(parent.get(v));
parent.put(v, p);
return p;
}