코딩테스트 연습 > 깊이/너비 우선 탐색(DFS/BFS) > 단어 변환
➡️ [ Java ] DFS(깊이 우선 탐색) vs BFS(너비 우선 탐색) 개념 정리
두 개의 단어 begin, target과 단어의 집합 words가 있습니다. 아래와 같은 규칙을 이용하여 begin에서 target으로 변환하는 가장 짧은 변환 과정을 찾으려고 합니다.
두 개의 단어 begin, target과 단어의 집합 words가 매개변수로 주어질 때, 최소 몇 단계의 과정을 거쳐 begin을 target으로 변환할 수 있는지 return 하도록 solution 함수를 작성해주세요.
begin | target | words | return |
---|---|---|---|
"hit" | "cog" | ["hot", "dot", "dog", "lot", "log", "cog"] | 4 |
"hit" | "cog" | ["hot", "dot", "dog", "lot", "log"] | 0 |
예제 #2
target인 "cog"는 words 안에 없기 때문에 변환할 수 없습니다.
class Dfs {
int answer = 0;
boolean[] visited; // 단어 방문 여부 체크
public int solution(String begin, String target, String[] words) {
visited = new boolean[words.length];
dfs(begin, target, words, 0);
return answer;
}
private void dfs(String begin, String target, String[] words, int cnt) {
if(begin.equals(target)) {
answer = cnt;
return;
}
for (int i=0; i<words.length; i++){
if(visited[i]){
continue;
}
// 한 단어에 같은 알파벳이 몇 개인지
int j = 0;
for(int k=0; k<begin.length(); k++){
if(begin.charAt(k) == words[i].charAt(k)){
j++;
}
}
// 한 글자 빼고 모두 같은 경우
if(j == begin.length() - 1){
// words[i] 단어를 방문했다고 표시
visited[i] = true;
// begin을 words[i]로 바꾸고 DFS 재귀 호출
dfs(words[i], target, words, cnt+1);
// 탐색이 끝나고 되돌아오면, 다시 방문 표시를 해제
// 다른 경로에서도 이 단어를 사용할 수 있어야 하니까, 사용하고 되돌아오면 방문 표시를 해제하기!
visited[i] = false;
}
}
}
}
한 경로를 끝까지 들어갔다가, 실패하면 다시 돌아와서 다른 경로를 보는 방식 = 깊이 우선 탐색 (DFS)
목표: begin
→ target
으로 가는 최단 경로(최소 단계 수) 구하기
==> 그래서 BFS (너비 우선 탐색) 방식이 더 적합
class Bfs {
public int solution(String begin, String target, String[] words) {
boolean[] visited = new boolean[words.length]; // 중복 방문 방지
Queue<Word> queue = new LinkedList<>(); // 탐색할 단어들을 Queue(큐) 에 저장
queue.offer(new Word(begin, 0)); // 시작 단어와 현재 깊이(0단계)
while (!queue.isEmpty()) {
// 현재 단어 꺼내기
Word current = queue.poll();
// 현재 단어가 target이면 종료, 변환 횟수 반환
if (current.word.equals(target)) {
return current.count; // 최단 거리 도달
}
// 인접한 단어들(한 글자만 다른)을 큐에 넣음
for (int i = 0; i < words.length; i++) {
if (!visited[i] && isOneLetterDifferent(current.word, words[i])) {
visited[i] = true;
queue.offer(new Word(words[i], current.count + 1));
}
}
}
return 0; // target에 도달할 수 없는 경우
}
// 한 글자 차이 판별 함수
private boolean isOneLetterDifferent(String a, String b) {
int diff = 0;
for (int i = 0; i < a.length(); i++) {
if (a.charAt(i) != b.charAt(i)) {
diff++;
}
}
return diff == 1;
}
class Word {
String word; // 현재 단어
int count; // 몇 단계(depth)인지
Word(String word, int count) {
this.word = word;
this.count = count;
}
}
}