단어변환
문제정의
시작단어에서 끝단어로 변환하는 최소 횟수를 알아내려고 한다. 만약 변환할 수 없다면 0을 반환한다. 변환을 거칠 땐 알파벳 한 글자만 바꿀 수 있다.
문제풀이
전체 코드는 다음과 같다. 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76import java.util.*;
public class TransformWord {
//프로그래머스 level3 단어 변환
public static int[][] matrix;
public static void main(String[] args) {
String begin = "hit";
String target = "cog";
String[] words = {"cog", "log", "lot", "dog", "dot", "hot"};
List<String> list = new ArrayList<String>();
list.add(begin);
for(String s : words)
list.add(s);
matrix = new int[list.size()][list.size()];
for(int i = 0; i < list.size(); i++)
{
for(int j = i+1; j < list.size(); j++)
{
if(canConnect(list.get(i), list.get(j)))
{
matrix[i][j] = 1;
matrix[j][i] = 1;
}
}
}
final int inf = 1250;
int[] distance = new int[list.size()];
boolean[] visited = new boolean[list.size()];
for(int i = 1; i < list.size(); i++)
distance[i] = inf;
Stack<Integer> stack = new Stack<>();
stack.push(0);
while(!stack.empty())
{
int root = stack.pop();
visited[root] = true;
for(int i = 0; i < list.size(); i++)
{
if(matrix[root][i] == 1 && !visited[i])
{
stack.push(i);
if(distance[i] > distance[root]+1)
distance[i] = distance[root]+1;
}
}
}
int index = list.indexOf(target);
if(index == -1 || distance[index] == inf)
System.out.println("false");
else
System.out.println(distance[index]);
}
public static boolean canConnect(String s1, String s2)
{
char[] arr1 = s1.toCharArray();
char[] arr2 = s2.toCharArray();
int wrong = 0;
for(int i = 0; i < arr1.length; i++)
{
if(arr1[i] != arr2[i])
++wrong;
}
return wrong == 1 ? true : false;
}
}
일단 그래프를 만들기 위해 두 단어가 변환이 되는 지 확인하는 함수 canConnect
를 정의하였다. 모든 단어의 길이는 같다고 했으므로, 한쪽의 길이를 기준으로 하여 문자를 비교한다. 만약 다른 글자수(wrong
)가 하나라면 true
를 반환하고, 아니라면 false
를 반환한다.
리스트 list
를 만들어 첫시간과 words를 합친다. 반복문을 통해 모든 쌍을 canConnect
를 통해 변환할 수 있는 관계인지 파악하고, 만약 변환할 수 있다면 matrix
에 1이라 표시한다(18-30줄).
그래프를 matrix
에 표시했으므로, dfs를 활용하여 최소 변환 횟수를 구할 차례이다. 이번 문제는 가능한 가 가능한지 않은가가 아니라, 최소를 찾아야 하므로 distance
를 추가로 선언한다. 시작단어인 distance[0]
은 0으로 하고 나머지는 큰 상수로 초기화한다.
이제 본격적인 dfs로 들어가보자. 스택에 0번을 넣고 vistied
(방문했는지 여부)를 true로 한다. 그리고 변환할 수 있는 단어 중에 아직 방문하지 않은 단어들의 인덱스를 담는다. 이 때, 변환 횟수를 비교하는데 만약 현재 단어가 가지고 있는 distance
값보다 현재 단어에서 1을 더한 값이 더 작다면 그 값으로 업데이트한다.
dfs를 모두 마치면 distance
에는 시작단어에서 각각의 모든 단어로 변환할 수 있는 최소 횟수가 담기게 된다. 이제 indexOf()
메소드를 이용하여 끝 단어의 인덱스를 구해 그 값을 반환하면 된다. 만약 끝단어의 distance
값이 무한이거나 없을 경우에는 false
를 출력하면 된다.
adjacency matrix를 사용하기 때문에, 최종 시간복잡도는 \(O(n^2)\)이다.
테스트
다른 사람의 풀이를 보니 그냥 dfs를 이용해서 풀었는데도 통과가 되었다. 그런데 그렇게 하면 최소값이 아니게 도달해도 정답이 되버릴텐데,, 이 부분에서 프로그래머스가 테스트 케이스를 추가해줬으면 좋겠다는 생각이 들었다.
이 문제를 풀면서 다익스트라를 참고도 안하고 혼자서 해보려고 했는데 나중에 다 풀고보니 다익스트라는 인접한 것 중에 가장 짧은 경로를 기준으로 가는 거라고 했다. 필자는 그냥 가장 나중에 확인한 것을 다음 노드로 지정하였는데 이렇게 해도 최단 거리를 찾을 수 있을지 궁금하다. 다음에 또 이런 문제를 만난다면 그 땐 다익스트라를 좀 더 세심하게 구현해야겠다. 덕분에 모자란 개념을 보충할 수 있었다.