와드의 블로그

[코딩테스트 독학] 코드트리와 깃허브 연동을 통해 매일 학습 루틴 만들기 본문

TIL

[코딩테스트 독학] 코드트리와 깃허브 연동을 통해 매일 학습 루틴 만들기

Ward 2026. 5. 20. 10:41

2회차에 걸쳐 갭체크 진단과 취약점(백트래킹) 보완을 마친 뒤, 이제는 코드트리의 학습 트레일을 따라 매일 꾸준히 학습하는 습관을 들이고 있습니다.

코딩 테스트는 단기간에 몰아서 하는 것보다 매일 조금씩이라도 꾸준히 감을 잃지 않는 것이 중요한데, 오늘은 제가 어떻게 학습 동기를 유지하고 루틴을 만들고 있는지에 대해 이야기해 보려 합니다.

깃허브(GitHub) 연동으로 잔디 심기

저는 기존에 백준이나 프로그래머스에서 문제를 풀 때 '백준허브'라는 크롬 익스텐션을 사용하여 깃허브에 코드를 자동 백업해 왔습니다. 내 학습 기록이 차곡차곡 쌓이는 것을 보는 것은 꽤나 큰 동기부여가 되거든요.

그런데 코드트리에서는 확장 프로그램 없이 플랫폼 자체에서 깃허브 저장소(Repository) 연동 기능을 완벽하게 지원합니다.

기존에 백준허브로 쓰던 저장소를 코드트리와 연동해 두니, 코드를 제출하고 정답을 맞힐 때마다 해당 문제에 대한 정보, 풀이 코드, 그리고 내 기록들이 알아서 깃허브에 Push됩니다. 단순히 코테 공부를 하는 것만으로도 잔디가 알아서 촘촘하게 심어지니 성취감이 배가 됩니다. 타 서비스들처럼 번거롭게 확장 프로그램을 깔거나 수동으로 올릴 필요 없이, 사이트 내 설정 몇 번만으로 완벽하게 연동되는 점이 정말 매력적입니다.

학습 리마인더 알림톡

매일 학습하겠다는 다짐은 종종 바쁜 일상에 치여 잊혀지기 쉽습니다. 코드트리에서는 학습 시간을 설정해 두면 카카오톡으로 학습 리마인더 알림톡을 보내줍니다.

퇴근 후 지쳐서 쉴까 하다가도, 알림톡이 오면 '아, 오늘 딱 한 문제만 풀자'라는 생각으로 노트북을 켜게 됩니다. 이 작은 알림 하나가 의지력을 크게 보완해 주어, 매일 지속적인 학습을 이어나가는 데 큰 체감 효과를 느끼고 있습니다.

앞으로 남은 챌린지 기간뿐만 아니라 그 이후에도 이 기능들을 활용해 꾸준한 학습 루틴을 정착시킬 수 있을 것 같습니다.

3주차 인상 깊었던 문제: 사다리 타기

이번 주에 풀었던 문제 중 로직을 짜는 데 가장 재미있었던 문제를 하나 소개합니다.

문제 개요

세로줄 N개와 가로줄 M개로 이루어진 사다리 타기 게임이 주어집니다. 목표는 초기 상태의 사다리 결과(각 출발점이 어떤 도착점으로 가는지)와 동일한 결과를 내는 사다리를 만들되, 가로줄을 최소한으로 사용하는 것입니다.

풀이 과정 및 접근 방식

  1. 가로줄 정렬 및 초기 결과 도출: 입력받은 가로줄들을 높이(b)를 기준으로 오름차순 정렬합니다. 사다리는 위에서 아래로 타야 하니까요. 그 후, 주어진 모든 가로줄을 사용했을 때의 결과 배열(target)을 미리 계산해 둡니다.
  2. 비트마스킹을 활용한 완전 탐색: 가로줄의 개수 M이 최대 15개로 매우 작습니다. 따라서 "이 가로줄을 사용할 것인가, 말 것인가?"에 대한 모든 경우의 수를 O(2^M)으로 탐색할 수 있습니다. 이를 구현하기 위해 0부터 2^M - 1까지 순회하며 비트마스킹을 적용했습니다.
  3. 최소 가로줄 개수 갱신: 각 비트 상태에 대해 check() 메서드를 호출합니다. 켜져 있는 비트에 해당하는 가로줄만 사용하여 새로운 결과 배열(pos)을 만들고, 이 배열이 초기에 구한 target 배열과 완벽히 일치하는지 확인합니다. 일치한다면 현재 사용한 가로줄의 개수(Integer.bitCount(i))를 세어 최솟값(ans)을 갱신합니다.

Java 제출 코드

import java.util.*;
import java.io.*;

public class Main {
    static class Line {
        int a, b;

        Line(int a, int b) {
            this.a = a;
            this.b = b;
        }
    }

    static int n, m;
    static Line[] lines;
    static int[] target;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

        StringTokenizer st = new StringTokenizer(br.readLine());
        n = Integer.parseInt(st.nextToken());
        m = Integer.parseInt(st.nextToken());
        lines = new Line[m];
        for (int i = 0; i < m; i++) {
            st = new StringTokenizer(br.readLine());
            int a = Integer.parseInt(st.nextToken());
            int b = Integer.parseInt(st.nextToken());
            lines[i] = new Line(a, b); // a: 시작 세로줄, b: 높이
        }

        // 높이를 기준으로 오름차순 정렬
        Arrays.sort(lines, (l1, l2) -> l1.b - l2.b);

        // 모든 가로줄을 사용했을 때의 타겟 배열(정답) 계산
        target = new int[n + 1];
        for (int i = 1; i <= n; i++) {
            target[i] = i;
        }
        for (int i = 0; i < m; i++) {
            int a = lines[i].a;
            int tmp = target[a];
            target[a] = target[a + 1];
            target[a + 1] = tmp;
        }

        int ans = m; // 최악의 경우, 모든 가로줄 사용
        
        // 비트마스킹을 이용해 가로줄의 부분 집합 탐색
        for (int i = 0; i < 1 << m; i++) {
            if (check(i)) {
                // 조건을 만족하면 켜진 비트 수(사용한 가로줄 수)로 최솟값 갱신
                ans = Math.min(ans, Integer.bitCount(i));
            }
        }

        bw.write(ans + "");
        bw.flush();
    }

    // 주어진 비트 상태(가로줄 조합)가 타겟 배열과 동일한 결과를 내는지 검증
    static boolean check(int x) {
        int[] pos = new int[n + 1];
        for (int i = 1; i <= n; i++) {
            pos[i] = i;
        }

        for (int i = 0; i < m; i++) {
            // i번째 가로줄을 사용하기로 했다면 (비트가 1이라면)
            if ((x & 1 << i) != 0) {
                int a = lines[i].a;
                int tmp = pos[a];
                pos[a] = pos[a + 1];
                pos[a + 1] = tmp;
            }
        }

        // 도출된 결과가 타겟과 완벽히 일치하는지 비교
        for (int i = 1; i <= n; i++) {
            if (pos[i] != target[i]) {
                return false;
            }
        }
        return true;
    }
}

마무리

2주차에 집중적으로 파고들었던 비트마스킹 기법을 이번 '사다리 타기' 문제에서 스스로 응용하여 풀었다는 점이 가장 뿌듯합니다.

앞으로도 코드트리와 깃허브가 만들어주는 든든한 환경 속에서, 알림톡의 도움을 받아 하루하루 성장해 나가는 기록을 차곡차곡 쌓아보겠습니다!