아래의 그림은 해결했던 과정을 그래프로 나타내었다.
ArrayList방문처리를 ArrayList에 현재 위치를 저장하여 contains로 포함 여부를 판단하려고 하니 시간 초과가 발생했다.
결론부터 말하면 ArrayList대신 HashSet을 사용했다.
ArrayList의 contains메서드는 내부 메서드인 indexOf를 활용하여 list의 수만큼 반복적으로 탐색하여 그만큼 부하가 발생하지만, HashSet의 contains메서드는 HashMap.containsKey를 활용하여 해시 코드가 일치하는 값과 비교 후 호출한다.
Collection 인터페이스를 상속받는 ArrayList와 HashSet은 contains메서드의 성능 차이는 여기서 확인한다.
[Java] Collection Interface란?
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
import java.util.HashSet;
public class Main {
static int N, K;
static int depth = 0; //술래가 찾는 시점
static Queue<Integer> que = new LinkedList<>();
static HashSet<Integer> hashSet = new HashSet<>();
static void bfs(int N, int queSize){
if(que.contains(K)){
return;
}
//현재 위치(노드)의 레벨에 있는 노드 수 만큼
for(int i=0; i<queSize; i++){
int curr = que.poll();
//현재 위치에서 이동할 수 있는 범위만큼 노드를 추가
int[] formula = new int[] {curr-1, curr+1, curr*2};
for(int j=0; j<formula.length; j++){
if(formula[j] >= 0 && formula[j] <= 100000 && !hashSet.contains(formula[j])){
que.add(formula[j]);
hashSet.add(formula[j]);
}
}
}
//이동할 수 있는 범위의 노드를 추가후 depth추가
depth++;
bfs(N, que.size());
}
public static void main(String[] args){
try{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
K = Integer.parseInt(st.nextToken());
} catch (IOException e){
e.printStackTrace();
}
if(N == K){
System.out.println(0);
}else if(N > K){
System.out.println(N-K);
}else{
que.add(N);
hashSet.add(N);
bfs(N,1);
System.out.println(depth);
}
}
}