Notice
Recent Posts
Recent Comments
Link
«   2024/09   »
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
Archives
Today
Total
관리 메뉴

Life Engineering

[프로그래머스] 단어 변환(DFS/BFS) 본문

Problem Solving

[프로그래머스] 단어 변환(DFS/BFS)

흑개 2021. 7. 15. 16:32

https://programmers.co.kr/learn/courses/30/lessons/43163

 

코딩테스트 연습 - 단어 변환

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

programmers.co.kr

 

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
#include <string>
#include <algorithm>
#include <vector>
#include <cstdlib>
#include <map>
#include <queue>
using namespace std;
 
void findNeighbor(string s, vector<string>& words, vector<string>& neighbors){
    neighbors.clear();
    int i,j;
    int count;
    int len=words[0].length();
    for (i=0; i<words.size(); i++){
        count=0;
        if (s.compare(words[i])!=0){
            for (j=0; j<len; j++){
                if (words[i][j]-s[j]==0){
                    count+=1;
                }
            }
            if (count==len-1){
                neighbors.push_back(words[i]);
            }
        }
    }
}
 
 
int solution(string beginstring target, vector<string> words) {
    map<stringint> visited;
    vector<string> neighbors;
    queue<string> q;
    int len=words[0].length();
    if (find(words.begin(), words.end(), target)==words.end()){
        return 0;
    }
    for (int i=0; i<words.size(); i++){
        visited[words[i]]=0;
    }
    q.push(begin);
    visited[begin]=1;
    while (!q.empty()){
        string x=q.front();
        q.pop();
        findNeighbor(x, words, neighbors);
        for (int i=0; i<neighbors.size(); i++){
            string y=neighbors[i];
            if (visited[y]==0){
                q.push(y);
                visited[y]=visited[x]+1;
            }
        }
    }
    return visited[target]-1;
}
cs

BFS 로 풀었다

좀 복잡하고 어렵고 코드 가독성이 gg다(오랜만에 코테 공부해서 그런가 더 나아질거라 믿는다)

 

1. words 목록에 target 없으면 0 리턴 후 종료

2. 그렇지 않으면 큐에 begin 넣어주고, visited에 1 해서 이동 거리를 나타낸다

3. 큐에서 다음 과정을 반복한다:

큐의 맨 첫번째 아이템을 pop하고, 그 단어의 neighbor 목록을 찾아, 방문하지 않은 neighbor 단어에 한해서만 큐에 push하고

이동거리+1 해서 visited를 표시한다

4. 큐가 비면 target 의 이동거리-1 해서 답을 구해준다

 

 

너무 어렵게 구한 것 같아 다른 분들의 풀이를 보니까

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
int visited[50];
 
int possible(string a, string b)
{
    int i;
    int cnt = 0;
 
    for(i=0;i<a.length();i++)
    {
        if(a[i] != b[i]) cnt++;
    }
 
    if(cnt==1return 1;
    else return 0;
}
 
int solution(string beginstring target, vector<string> words) {
    int answer = 0;
    queue<pair<string,int>> Q;
    int i;
    string temp;
    int num;
 
    Q.push(make_pair(begin,0));
    while(!Q.empty())
    {
        temp = Q.front().first;
        num = Q.front().second;
        Q.pop();
 
        if(temp.compare(target) == 0)
        {
            answer = num;
            break;
        }
 
        for(i=0;i<words.size();i++)
        {
            if(visited[i]) continue;
            if(possible(temp, words[i]))
            {
                visited[i] = 1;
                Q.push(make_pair(words[i],num+1));
            }
        }
    }
 
    return answer;
}
cs

출처: 프로그래머스 김영진,김명권 님

애초에 neighbors를 큐의 맨 첫번째 아이템에서 다 구할 필요 없다. 

첫번째 아이템을 pop 한 후, words를 돌면서 방문하지 않은 항목에 대해서만 이웃이 될 수 있는지 체크한다.

체크 함수는 나와 비슷한 아이디어로, 한글자씩 비교해서 동일하지 않은 문자의 개수가 1개일 경우일 때만 이웃으로 간주한다.

나처럼 한꺼번에 neighbor 목록을 구하는 방식이 아니라 words를 돌면서 방문하지 않은 것에 대해 이웃인지 체크한 후, 그것을 큐에 넣어주는 방식을 취했다. 

또 한가지 배워야 할 점은 나는 visited에 이동거리를 넣어 방문여부도 체크하고, 이동거리도 알 수 있도록 했는데 이분들은 아예 큐에 pair를 넣어줬다. string, int로 구성되며 int는 이동 횟수를 나타낸다. 방문여부를 나타내는 visited 배열은 따로 빼주었다. 이웃이고+미방문 문자열일 경우에 pair의 num 부분을 본인 num+1 해서 이동횟수를 나타내었다.

 

 간단하게 이웃인지 체크하는 함수를 만들자(개별 item으로)!! 한꺼번에 neighbor 배열 넣는건 좀 복잡해보인다.