Theme:

문제를 읽고 30초 안에 "이건 이분 탐색이다" 또는 "이건 DP다"라고 판단할 수 있다면, 절반은 푼 것입니다.

입력 크기로 알고리즘 고르기

코딩 테스트에서 가장 중요한 첫 단계는 N의 범위를 확인하는 것 입니다. 시간 제한이 보통 1~2초이고, 1초에 약 1억(10^8) 번 연산이 가능하다고 가정하면 아래 표가 나옵니다.

N의 범위허용 복잡도대표 알고리즘
N ≤ 10O(N!)완전 탐색, 순열
N ≤ 20O(2^N)비트마스킹, 백트래킹
N ≤ 50O(2^(N/2))Meet in the Middle
N ≤ 500O(N³)Floyd-Warshall, DP
N ≤ 5,000O(N²)2중 루프 DP, 정렬
N ≤ 100,000O(N log N)정렬, 이분 탐색, 세그먼트 트리
N ≤ 1,000,000O(N)투 포인터, 해시, 그리디
N ≤ 10^9O(log N) ~ O(√N)이분 탐색, 수학

이 표가 절대적인 것은 아니지만, 알고리즘 선택의 강력한 가이드가 됩니다.

유형별 판별 키워드

그래프 탐색 (BFS/DFS)

**키워드 **: "연결", "영역", "최단 거리", "갈 수 있는", "미로"

PLAINTEXT
- 연결 요소의 수 → DFS/BFS + 방문 체크
- 최단 거리 (가중치 없음) → BFS
- 모든 경우 탐색 → DFS + 백트래킹
- 격자에서 영역 구분 → Flood Fill (BFS/DFS)
JAVA
// BFS 최단 거리 — 격자
public int bfs(int[][] grid, int[] start, int[] end) {
    int rows = grid.length, cols = grid[0].length;
    int[][] dist = new int[rows][cols];
    for (int[] row : dist) Arrays.fill(row, -1);

    Queue<int[]> queue = new LinkedList<>();
    queue.offer(start);
    dist[start[0]][start[1]] = 0;

    int[] dx = {0, 0, 1, -1};
    int[] dy = {1, -1, 0, 0};

    while (!queue.isEmpty()) {
        int[] curr = queue.poll();
        for (int d = 0; d < 4; d++) {
            int nx = curr[0] + dx[d], ny = curr[1] + dy[d];
            if (nx >= 0 && nx < rows && ny >= 0 && ny < cols
                && grid[nx][ny] != 1 && dist[nx][ny] == -1) {
                dist[nx][ny] = dist[curr[0]][curr[1]] + 1;
                if (nx == end[0] && ny == end[1]) return dist[nx][ny];
                queue.offer(new int[]{nx, ny});
            }
        }
    }
    return -1;
}

동적 프로그래밍 (DP)

** 키워드 **: "최소/최대", "경우의 수", "가능한지 여부", "부분 문제"

PLAINTEXT
- "최소 비용으로 ~하라" → DP
- "~하는 경우의 수" → DP
- "~가 가능한가?" → DP (또는 그리디)
- 최적 부분 구조 + 중복 부분 문제 → DP

이분 탐색

** 키워드 **: "최솟값의 최댓값", "최댓값의 최솟값", "K번째", "조건을 만족하는 ~"

PLAINTEXT
- "최소 시간으로 모두 처리" → 매개변수 탐색
- "N개 중 K번째로 큰 수" → 이분 탐색
- 답의 범위가 크지만 단조성이 있을 때 → 이분 탐색
JAVA
// 매개변수 탐색 — "최소 시간으로 모두 처리"
public long parametricSearch(int[] tasks, int workers) {
    long lo = 1, hi = 1_000_000_000L;

    while (lo < hi) {
        long mid = (lo + hi) / 2;
        if (canFinish(tasks, workers, mid)) {
            hi = mid;
        } else {
            lo = mid + 1;
        }
    }
    return lo;
}

private boolean canFinish(int[] tasks, int workers, long time) {
    // time 시간 안에 workers명으로 모든 tasks를 처리할 수 있는지 확인
    long count = 0;
    for (int task : tasks) {
        count += time / task;
    }
    return count >= workers;
}

그리디

** 키워드 **: "최대한 많이", "정렬 후 선택", "매 순간 최선"

PLAINTEXT
- 활동 선택 문제 → 끝나는 시간 기준 정렬
- 배낭 문제 (분할 가능) → 단위 가치 기준 정렬
- 허프만 코딩 → 빈도 기준 우선순위 큐

투 포인터 / 슬라이딩 윈도우

** 키워드 **: "연속 부분", "부분 배열의 합", "정렬된 배열에서 쌍 찾기"

JAVA
// 투 포인터 — 합이 target인 쌍 찾기
public int[] twoSum(int[] sorted, int target) {
    int left = 0, right = sorted.length - 1;
    while (left < right) {
        int sum = sorted[left] + sorted[right];
        if (sum == target) return new int[]{left, right};
        else if (sum < target) left++;
        else right--;
    }
    return new int[]{-1, -1};
}

// 슬라이딩 윈도우 — 길이 K인 부분 배열의 최대 합
public int maxSumSubarray(int[] arr, int k) {
    int sum = 0;
    for (int i = 0; i < k; i++) sum += arr[i];

    int maxSum = sum;
    for (int i = k; i < arr.length; i++) {
        sum += arr[i] - arr[i - k]; // 윈도우 이동
        maxSum = Math.max(maxSum, sum);
    }
    return maxSum;
}

최단 경로

PLAINTEXT
가중치 없음 → BFS
양의 가중치 → Dijkstra
음의 가중치 → Bellman-Ford
모든 쌍 최단 경로 (N ≤ 500) → Floyd-Warshall

문자열

PLAINTEXT
패턴 매칭 → KMP
여러 문자열의 공통 부분 → Trie
부분 문자열 비교 → 해싱 (Rabin-Karp)

문제 접근 프레임워크

문제를 읽고 아래 순서로 생각합니다.

PLAINTEXT
1. N의 범위 확인 → 허용 복잡도 결정
2. 키워드/패턴 인식 → 유형 분류
3. 예제를 손으로 풀어보기 → 패턴 확인
4. 알고리즘 선택 → 구현
5. 예외 케이스 확인 → 빈 입력, 최대/최소, 음수

자주 출제되는 패턴 조합

패턴예시
정렬 + 이분 탐색"K번째 원소 찾기"
BFS + DP"최단 경로에서의 최소 비용"
그래프 + Union-Find"네트워크 연결 문제"
문자열 + 해시"부분 문자열 비교"
트리 + DFS"서브트리의 합/최대값"
매개변수 탐색 + 그리디"조건을 만족하는 최솟값"

백엔드/실무 연결

코딩 테스트 알고리즘은 실무와 직접 연결됩니다.

  • ** 이분 탐색** → DB 인덱스 검색 (B+Tree)
  • BFS → 소셜 네트워크 친구 추천 (N촌 관계)
  • DP → 캐싱 전략, 최적 쿼리 계획
  • ** 그리디** → 스케줄링, 리소스 할당
  • ** 해시** → 캐시, 로드밸런싱, 중복 제거

주의할 점

입력 크기만 보고 알고리즘을 단정짓는 실수

n이 100,000이라고 반드시 O(n log n)만 가능한 것은 아닙니다. 상수 계수가 작은 O(n log n)과 상수가 큰 O(n)은 실제 실행 시간이 비슷할 수 있습니다. 입력 크기는 참고 지표이지 절대 기준이 아닙니다.

최적화를 급히 적용하여 정확성을 잃는 실수

시간 초과가 나면 최적화를 해야 하지만, 최적화 과정에서 코너 케이스를 빠뜨리면 오답이 됩니다. 먼저 정확한 브루트포스를 구현하고, 이를 기준으로 최적화 풀이를 검증해야 합니다.


정리

  • N의 범위 를 보고 허용 가능한 시간 복잡도를 먼저 판단합니다
  • 키워드 로 유형을 빠르게 분류합니다 (최단 거리 → 그래프, 경우의 수 → DP 등)
  • 정렬 + 이분 탐색, BFS + DP 같은 조합 패턴 을 익혀두면 응용력이 높아집니다
  • 예제를 손으로 풀어보는 것이 알고리즘 선택에 큰 도움이 됩니다
  • 코딩 테스트 알고리즘은 실무의 DB 인덱스, 캐싱, 스케줄링 등과 직접 연결됩니다
댓글 로딩 중...