자바스크립트 코딩테스트 강좌, 거짓말쟁이가 되긴 싫어

코딩테스트는 많은 개발자들이 겪는 어려운 과정입니다. 특히 자바스크립트로 문제를 해결해야 할 때는 언어의 특성을 잘 이해하고 있어야 합니다. 이번 강좌에서는 ‘거짓말쟁이가 되긴 싫어’라는 문제를 통해 자바스크립트의 특성과 알고리즘 접근 방식을 살펴보겠습니다.

문제 설명

다음과 같은 상황을 상상해보세요. 당신은 여러 친구와 함께 캠프를 가고 있습니다. 친구들 중 일부는 괴짜들이어서, 어떤 특정 사건에 대해서는 거짓말을 하기로 결심했습니다. 다음은 각 친구들이 이야기한 내용입니다.

주어진 입력은 배열로 표현되며, 각 배열의 값은 친구들이 주장하는 친구의 숫자입니다. 당신의 목표는 주장에 맞는 친구의 수가 다수일 때, 그 친구들이 거짓말을 하고 있다고 판단하는 것입니다.

예시 입력

    const statements = [
        [0, 1], // 친구 0은 친구 1을 주장
        [1, 2], // 친구 1은 친구 2를 주장
        [2, 0], // 친구 2는 친구 0을 주장
        [3, 2], // 친구 3은 친구 2를 주장 (여기서 친구 3은 거짓말쟁이다)
    ];
    

예시 출력

거짓말을 하는 친구의 수: 1

문제 해결 과정

이 문제에 접근하는 첫 번째 단계는 각 친구가 누군가를 주장하는 관계를 이해하는 것입니다. 여기서는 유향 그래프를 사용하여 각각의 친구를 노드로, 주장하는 관계를 간선으로 나타낼 수 있습니다.

1. 데이터 구조 설계

우선, 각 친구에 대한 주장을 저장할 수 있는 자료구조를 정의해야 합니다. 이를 위해 객체를 사용하여 친구의 ID와 그 친구가 주장하는 친구의 ID의 목록을 맵핑할 수 있습니다.

    const graph = {};
    statements.forEach(([speaker, listener]) => {
        if (!graph[speaker]) {
            graph[speaker] = [];
        }
        graph[speaker].push(listener);
    });
    

2. DFS/BFS를 통한 탐색

주장 간의 관계를 탐색하기 위해 DFS(깊이 우선 탐색) 혹은 BFS(너비 우선 탐색)를 사용할 수 있습니다. 이렇게 하면 각 친구의 주장이 유효한지를 확인할 수 있습니다.

    function hasContradictions(speaker) {
        const visited = new Set();
        const stack = [speaker];

        while (stack.length) {
            const curr = stack.pop();
            if (visited.has(curr)) {
                return true; // 이미 방문한 노드를 다시 방문할 경우 모순 발생
            }
            visited.add(curr);

            if (graph[curr]) {
                graph[curr].forEach(listener => {
                    stack.push(listener);
                });
            }
        }
        return false;
    }
    

3. 전체 친구에 대해 확인

모든 친구를 확인하여, 주장이 유효하지 않은 친구의 수를 셉니다. 전체 친구의 수중 몇 명이 모순을 만드는지를 파악하는 과정입니다.

    let liarsCount = 0;
    for (let i = 0; i < statements.length; i++) {
        if (hasContradictions(i)) {
            liarsCount++;
        }
    }
    return liarsCount;
    

최종 코드

    function findLiars(statements) {
        const graph = {};
        statements.forEach(([speaker, listener]) => {
            if (!graph[speaker]) {
                graph[speaker] = [];
            }
            graph[speaker].push(listener);
        });

        function hasContradictions(speaker) {
            const visited = new Set();
            const stack = [speaker];

            while (stack.length) {
                const curr = stack.pop();
                if (visited.has(curr)) {
                    return true; 
                }
                visited.add(curr);

                if (graph[curr]) {
                    graph[curr].forEach(listener => {
                        stack.push(listener);
                    });
                }
            }
            return false;
        }

        let liarsCount = 0;
        for (let i = 0; i < statements.length; i++) {
            if (hasContradictions(i)) {
                liarsCount++;
            }
        }
        return liarsCount;
    }

    console.log(findLiars(statements)); // 출력: 1
    

결론

위와 같은 문제를 통해 자바스크립트의 기본 문법, 자료구조 활용, 그리고 DFS/BFS 알고리즘을 적용하는 법을 배웠습니다. 코딩테스트 준비 시 이러한 문제들을 연습하여 알고리즘적 사고를 키우는 것이 중요합니다.