프린세스 다이어리

[Algospot] 고대어 사전 문제 자바스크립트 풀이 본문

자료구조, 알고리즘

[Algospot] 고대어 사전 문제 자바스크립트 풀이

개발공주 2022. 4. 17. 17:58
728x90

1. 풀이 순서

  • 문제 입력에 따라 2차원 배열을 만들어주는 함수를 하나 만든다.(makeGraph)
  • dfsAll() 수행하여, dfs() 종료 시마다 현재 정점을 기록한다.(order)
  • 위상정렬 결과를 얻기 위해 그 기록을 뒤집어서 결과를 도출한다.(order.reverse())
  • 추가로 DAG 조건에 부합하는지 검사하여 예외처리 한다.

2. 해답

const makeGraph = (numOfTest, words) => {
    // 1. 2차원 배열을 26*26 크기로 초기화해줌.
    let graph = Array.from(Array(26), () => Array(26).fill(0)); 

    // 2. 들어온 단어들을 돌아줌. 이 케이스에서는 나름의 알파벳 순서대로 정렬돼 있으므로 지금거([j])랑 이전거([j-1=i])랑 비교해서 graph에 간선 1로 표시해줌
    for (let j = 1; j < numOfTest; j++) {
        const i = j - 1;
        // 단어가 길어도 둘중 짧은 단어 까지만 이중포문 돌면 되니까 min으로 length 제한해줌.
        const length = Math.min(words[i].length, words[j].length); 

		// 3. min 길이까지 단어 알파벳을 돌아줌. 알파벳을 2차원 배열의 인덱스화하기 위해 charCodeAt 써줘서 두번째, 세번째, 그 이상 자릿수끼리 for문돌며 비교함
        for (let k = 0; k < length; k++) {
            if (words[i][k] !== words[j][k]) {
                const a = words[i][k].charCodeAt(0) - "a".charCodeAt(0);
                const b = words[j][k].charCodeAt(0) - "a".charCodeAt(0);
                graph[a][b] = 1;
                break; // 알파벳을 도는 for문은 한 번 서로 다른 알파벳이 발견되면 그것까지만 간선으로 연결 후 멈춤.
            }
        }
    }
    return graph;
};

const topologicalSort = (numOfTest, words) => {
    const graph = makeGraph(numOfTest, words);
    const length = graph.length;

    let order = [];
    let visited = Array(26).fill(false);

    /**
     * 깊이 우선 탐색 dfs
     */
    const dfs = (here) => {
        visited[here] = true;

        for (let there = 0; there < length; there++) {
            if (graph[here][there] && !visited[there]) {
                // (u, v)간선이 있는데 방문을 안한 v가 있다면 방문처리하기.
                dfs(there);
            }
        }
        // 위상정렬 결과 얻기 위해 dfs() 종료 시마다 현재 정점 기록. 그 기록 순서를 뒤집으면 위상정렬 결과임
        order.push(here); 
    };

    /**
     * 전체 노드에 대한 깊이 우선 탐색인 dfsAll() 역할
     */
    for (let i = 0; i < length; i++) {
        if (!visited[i]) {
            dfs(i);
        }
    }

    /**
     * 위상정렬 결과 도출하기 위하여 순서 뒤집는다.
     */
    order.reverse();

    /**
     * 문제 요구사항에서 위상정렬 여부를 판단해야 하므로
     * 그래프를 2중 for문을 돌면서, 반대로(n -> m) 연결된 간선이 있으면 빈 배열 리턴한다.(반대 간선 있으면 사이클이기 때문.)
     */
    for (let m = 0; m < length; m++) {
        for (let n = m + 1; n < length; n++) {
            if (graph[order[n]][order[m]]) {
                order = [];
            }
        }
    }

    /**
     * 문제 요구사항 도출 위해 order 값을 알파벳으로 변환, 또는 "INVALID HYPOTHESIS" 리턴.
     */
    let answer;
    if (order.length === 0) {
        answer = "INVALID HYPOTHESIS";
    } else {
        answer = order
            .map((num) => {
                const code = num + "a".charCodeAt(0);
                return String.fromCharCode(code);
            })
            .join("");
    }
    console.log(answer);
    return answer;
};

 

3. 결과

topologicalSort(5, ["gg", "kia", "lotte", "lg", "hanwha"]);
// zyxwvutsrqponmjigklhfedcba - 위상위상정렬 특성상 여러 답이 존재할 수 있는데, 
// 선후관계가 위반하지 않으면 남은 알파벳은 어떤 순서든 상관 없다.
// o-g-k-l-h 순서만 맞으면 됨.

topologicalSort(3, ["ba", "aa", "ab"]);
// INVALID HYPOTHESIS

topologicalSort(6, [
    "dictionary",
    "english",
    "is",
    "ordered",
    "ordinary",
    "this",
]);
// zyxwvusrqpnmlkjhgfdeiotcba
// d-e-i-o-t

이게 난이도 하라고?~ㅋ

728x90
Comments