프로그래머스: 단어 변환⭐⭐⭐

업데이트:     Updated:

카테고리:

태그: , , ,

난이도 ⭐⭐⭐
유형 : DFS/BFS(탐색), 백트래킹

🧐 문제

문제 설명

두 개의 단어 begin, target과 단어의 집합 words가 있습니다. 아래와 같은 규칙을 이용하여 begin에서 target으로 변환하는 가장 짧은 변환 과정을 찾으려고 합니다.

1. 한 번에 한 개의 알파벳만 바꿀 수 있습니다.
2. words에 있는 단어로만 변환할 수 있습니다.

예를 들어 begin이 “hit”, target가 “cog”, words가 [“hot”,”dot”,”dog”,”lot”,”log”,”cog”]라면 “hit” -> “hot” -> “dot” -> “dog” -> “cog”와 같이 4단계를 거쳐 변환할 수 있습니다.

두 개의 단어 begin, target과 단어의 집합 words가 매개변수로 주어질 때, 최소 몇 단계의 과정을 거쳐 begin을 target으로 변환할 수 있는지 return 하도록 solution 함수를 작성해주세요.

제한사항

  • 각 단어는 알파벳 소문자로만 이루어져 있습니다.
  • 각 단어의 길이는 3 이상 10 이하이며 모든 단어의 길이는 같습니다.
  • words에는 3개 이상 50개 이하의 단어가 있으며 중복되는 단어는 없습니다.
  • begin과 target은 같지 않습니다.
  • 변환할 수 없는 경우에는 0를 return 합니다.

입출력 예

begin target words return
“hit” “cog” [“hot”, “dot”, “dog”, “lot”, “log”, “cog”] 4
“hit” “cog” [“hot”, “dot”, “dog”, “lot”, “log”] 0

입출력 예 설명

예제 #1
문제에 나온 예와 같습니다.

예제 #2
target인 “cog”는 words 안에 없기 때문에 변환할 수 없습니다.


🔍 힌트

DFS/BFS를 사용하여 탐색하는 방법을 사용하여야 한다.

현재 단어에서 단 한글자만 다른 단어들을 방문하고, 방문처리하면 된다.
방문처리할 때는 백트래킹을 사용하면 쉽게 풀 수 있다.


✏️ 나의 풀이

#include <bits/stdc++.h>

using namespace std;

unordered_map<string, bool> visited;
int min_step = INT_MAX;

void dfs(string cur, const string target, vector<string>& words, int step) {
    
    if(min_step<=step) return;
    
    if(cur == target) {
        min_step = step;
        return;
    }
    
    for(string word : words) {
        for(int i=0; i<cur.size(); i++) {

            string cp_cur = cur;
            string cp_word = word;
            
            cp_cur.erase(i,1);
            cp_word.erase(i,1);
            
            if(cp_cur == cp_word && !visited[cur]) {
                visited[cur] = true;
                dfs(word, target, words, step+1);
                visited[cur] = false;
            }

        }
    }
    
}

int solution(string begin, string target, vector<string> words) {
    
    dfs(begin, target, words, 0);
    if(min_step == INT_MAX) min_step = 0;
    
    return min_step;
}

✔️ 다른 사람의 풀이

#include <string>
#include <vector>
#include <algorithm>
using namespace std;

int answer = 50;
bool visited[50];

//다른 문자가 1개인지 확인하는 함수
bool check_diff(string a, string b){
  int dif_cnt =0;

  for(int i=0; i<a.size();i++){
    if(a[i]!=b[i]){
      dif_cnt++;
    }
  }
  // 다른 문자가 1개일때
  if(dif_cnt==1){
    return true;
  }
  // 다른문자가 한개가 아닐때
  return false;
}

void dfs(string begin, string target,vector<string>words,int step){
  // step이 이전에 찾은 answer보다 크면 탐색할 필요가 없다
  if(answer <= step)
    return;

  if(begin==target){
    answer = min(answer,step);
    return;
  }
  
  for(int i=0; i<words.size();i++){
    // 한개의 문자만 다르고 방문 하지 않은 단어이면 탐색 시작
    if(check_diff(begin,words[i]) && !visited[i]){
      visited[i]=true;
      // 그 단어부터 탐색을 다시 시작한다. 단계가 하나 추가되었으므로 step+1을 인자로 넘긴다.
      dfs(words[i],target,words,step+1);
      // dfs 재귀 호출하여 종료되어 여기로 돌아오면, 백트래킹 (방문 표시 해제) 하여 다음분기점부터 다시 탐색을 시작한다.
      visited[i]=false;
    }
  }
  
  return;
}

int solution(string begin, string target, vector<string> words) {
  dfs(begin,target,words,0);

  // 탐색후 target문자열을 만나지 못했을 때
  if(answer == 50)
    return 0;

  return answer;
}

🧐 분석

  1. 나는 string의 erase와 비교 연산자를 통해, 한 글자만 다른 단어들을 찾았다.
    하지만 다른 사람의 풀이에선 check_diff 함수를 통해, 다른 글자의 개수를 세줌으로써 원하는 단어들을 찾아내고 있다.
    다른 글자의 개수를 세는 방법이 최적화에 더 도움이 되는 방법이므로, 나보다 더 좋은 풀이이다.
  2. 이 문제또한 문제 풀이의 방법이 대부분 다 비슷했다.

Programmers 카테고리 내 다른 글 보러가기

댓글남기기