[2026] 코딩 테스트 완벽 대비 가이드 | 알고리즘부터 실전 팁까지

[2026] 코딩 테스트 완벽 대비 가이드 | 알고리즘부터 실전 팁까지

이 글의 핵심

투 포인터·슬라이딩 윈도우·이진 탐색·BFS/DFS부터 DP·그리디·최단경로·위상정렬·트라이까지, 왜 쓰는지와 흔한 실수까지 풀어 쓴 뒤 자료구조·패턴·시간 배분·언어 선택으로 이어집니다.

들어가며: 코딩 테스트는 준비가 전부

”알고리즘을 몰라서 떨어졌어요”

코딩 테스트는 패턴 인식입니다. 자주 나오는 패턴을 익히고, 반복 연습하면 누구나 통과할 수 있습니다. 다만 현장에서는 “이름”보다 제약 조건과 시간 복잡도가 먼저 말을 겁니다. n이 10만이면 O(n²)은 대개 버티기 어렵고, n이 20이면 지옥 같은 브루트포스도 허용되기도 해요. 그래서 알고리즘을 공부할 때는 “언제 쓰이고, 언제 틀리는지”를 같이 적어 두면 나중에 시험장에서 훨씬 덜 헤맙니다. 이 글에서 다루는 것:

  • 필수 알고리즘 및 자료구조
  • 문제 풀이 패턴
  • 시간 관리 전략
  • 언어 선택 가이드
  • 실전 팁

코딩 테스트 준비하며 깨달은 것

알고리즘 문제를 풀다 보면 “이게 실무에 무슨 도움이 될까?” 하는 의문이 들 때가 있습니다. 저도 그랬습니다. 하지만 실제 프로젝트에서 성능 문제에 부딪히면, 알고리즘 지식이 얼마나 중요한지 깨닫게 됩니다. 예를 들어, 사용자 검색 기능이 느려서 고민하다가 해시 테이블을 적용하니 응답 시간이 10초에서 0.1초로 줄어든 경험이 있습니다. 코딩 테스트는 단순히 취업을 위한 관문이 아니라, 문제 해결 능력을 키우는 훈련장입니다. 처음엔 브루트 포스로 풀다가, 시간 복잡도를 개선하는 과정에서 “아, 이렇게 생각하면 되는구나” 하는 깨달음을 얻을 때의 쾌감은 말로 표현하기 어렵습니다. 이 글에서는 단순히 정답 코드만 제시하는 게 아니라, 문제를 어떻게 접근하고 최적화하는지 사고 과정을 함께 공유하겠습니다.

목차

  1. 필수 알고리즘
  2. 필수 자료구조
  3. 문제 풀이 패턴
  4. 시간 관리
  5. 언어 선택
  6. 실전 팁
  7. 정리

1. 필수 알고리즘

알고리즘 이름만 외우면 시험장에서 잘 안 떠오릅니다. 대신 “이 문제는 뭘 줄이려고 하는가?”를 머릿속에 그려 두는 편이 낫습니다. 배열을 두 번 도는 걸 한 번으로 줄이면 투 포인터나 슬라이딩 윈도우, 결정 문제(정답이 X 이상인가?)를 반복해서 물으면 이진 탐색, 연결 관계를 한 덩어리씩 관리하면 그래프 탐색 쪽을 떠올리면 됩니다. 아래 코드는 뼈대이고, 그 아래 글은 시험에서 실제로 판단할 때 쓰는 말입니다.

우선순위별 학습 순서

다음은 mermaid를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

graph TB
    A[코딩 테스트 알고리즘] --> B[1단계: 필수]
    A --> C[2단계: 중요]
    A --> D[3단계: 고급]
    
    B --> B1[투 포인터]
    B --> B2[슬라이딩 윈도우]
    B --> B3[이진 탐색]
    B --> B4[BFS/DFS]
    
    C --> C1[동적 프로그래밍]
    C --> C2[그리디]
    C --> C3[백트래킹]
    
    D --> D1[최단 경로]
    D --> D2[위상 정렬]
    D --> D3[트라이]

1단계: 필수 알고리즘 (출제 빈도 높음)

투 포인터

한 줄 요약: 정렬이 되어 있거나, 앞뒤에서 동시에 좁혀도 “후보가 갈리는” 구조일 때 쓰는 기법입니다. 이중 for문으로 O(n²) 나올 것을 O(n)으로 내리는 패턴이 꽤 많습니다. 시험에서 보통 이렇게 접근합니다. 합이 목표보다 작으면 왼쪽 포인터만 늘리면 합이 커지고, 크면 오른쪽만 줄이면 합이 작아집니다. 배열이 오름차순이라는 전제가 있으면 “이제 후보를 버리는 지점이 명확하다”는 뜻이에요. 반대로 정렬이 없는데 투 포인터만 억지로 쓰면 막히거나 증명이 안 됩니다. 그때는 해시로 역할을 나누거나, 먼저 정렬해도 되는지(인덱스가 중요한지)부터 봐야 합니다. 대표적인 함정은 두 가지입니다. 하나는 left < rightleft <= right를 헷갈리는 것(문제마다 “같은 원소 두 번 써도 되는지”가 다름). 다른 하나는 중복 제거(정렬 후 nums[i] == nums[i-1] 스킵 같은 처리)를 빼먹어서 시간 초과나 오답 나는 경우입니다. 다음은 python를 활용한 상세한 구현 코드입니다. 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 예제: 정렬된 배열에서 두 수의 합
def two_sum(arr, target):
    left, right = 0, len(arr) - 1
    
    while left < right:
        current_sum = arr[left] + arr[right]
        if current_sum == target:
            return [left, right]
        elif current_sum < target:
            left += 1
        else:
            right -= 1
    
    return None
# 시간복잡도: O(n)

슬라이딩 윈도우

한 줄 요약: “연속된 구간”의 합·개수·특성을 매번 처음부터 다시 계산하지 않고, 한 칸 밀 때 들어온 값과 나간 값만 반영합니다. 고정 길이 k면 구현이 단순합니다. 한 윈도우의 합을 구해 두고, 오른쪽으로 한 칸 갈 때 + arr[i] - arr[i-k]만 하면 됩니다. 가변 길이(조건을 만족하는 최소/최대 길이)는 오른쪽으로 늘리다가 조건이 깨지면 왼쪽을 당겨 맞추는 식으로 많이 풉니다. 이때 “왼쪽을 얼마나 당겨야 하는가?”가 문제의 핵심인 경우가 많고, 보통은 카운터(문자 개수, 조건 카운트)를 같이 들고 움직입니다. 투 포인터랑 겹쳐 보이는데, 슬라이딩 윈도우는 구간이 연속이라는 전제가 더 분명합니다. “부분 수열”처럼 연속이 아니면 이 패턴이 아닙니다. 아래 코드는 python를 사용한 구현 예제입니다. 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 예제: 길이 k인 부분 배열의 최대 합
# 함수 정의 및 구현
def max_sum_subarray(arr, k):
    window_sum = sum(arr[:k])
    max_sum = window_sum
    
    for i in range(k, len(arr)):
        window_sum += arr[i] - arr[i - k]
        max_sum = max(max_sum, window_sum)
    
    return max_sum
# 시간복잡도: O(n)

이진 탐색

한 줄 요약: 정렬된 배열에서만 도는 게 아니라, “답이 X일 수 있나?”에 true/false가 단조로울 때 경계를 반으로 자르는 도구로 더 많이 씁니다. 코딩 테스트에서 제일 흔한 형태는 두 가지입니다. 하나는 전형적인 “있는지 찾기”(위 코드). 다른 하나는 lower_bound 류: “target 이상이 처음 나오는 위치”“조건을 만족하는 최소/최대 값”을 찾는 것입니다. 후자는 while left < rightmid 계산을 (left + right) // 2로 할지 올림으로 할지에 따라 하루 종일 헷갈립니다. 여기서는 원칙만 짚을게요: 루프 불변식(left/right가 답이 들어갈 구간의 양 끝을 나타낸다)을 종이에 한 줄 적어 두고 짜면 사고 시간이 확 줄어요. 실수 포인트는 mid = (left + right) // 2에서 큰 정수일 때 오버플로가 나는 언어(C++/Java 등) left + (right - left) // 2 습관이 안전합니다. Python은 덜하지만, 개념은 같습니다. 다음은 python를 활용한 상세한 구현 코드입니다. 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 예제: 정렬된 배열에서 값 찾기
def binary_search(arr, target):
    left, right = 0, len(arr) - 1
    
    while left <= right:
        mid = (left + right) // 2
        if arr[mid] == target:
            return mid
        elif arr[mid] < target:
            left = mid + 1
        else:
            right = mid - 1
    
    return -1
# 시간복잡도: O(log n)

BFS와 DFS

한 줄 요약: 둘 다 “그래프나 트리를 한 번씩 질서 있게 도는 방법”인데, 큐를 쓰느냐 스택(재귀)을 쓰느냐 차이가 거의 전부입니다. BFS는 가까운 쪽부터 퍼집니다. 그래서 미로에서 최단 거리(가중치 없을 때), 트리에서 레벨별 순회, 상태 공간이 넓은데 깊이 제한이 명확한 문제에 잘 맞습니다. DFS는 한 길을 끝까지 파고들었다가 되돌아옵니다. 모든 경로/부분집합을 조사하거나, 백트래킹과 같이 “선택했다가 취소”하는 구조와 잘 맞습니다. 시험에서 DFS 재귀가 깊어지면(최악 수만 오) 재귀 한도에 걸릴 수 있습니다. 그때는 명시적 스택으로 DFS를 구현하거나, BFS로 바꿀 수 있는지 보면 됩니다. visited를 안 하면 순환 그래프에서 무한 루프 나는 건 기본 중의 기본입니다. 다음은 python를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

from collections import deque
# BFS
def bfs(graph, start):
    visited = set()
    queue = deque([start])
    visited.add(start)
    
    while queue:
        node = queue.popleft()
        print(node)
        
        for neighbor in graph[node]:
            if neighbor not in visited:
                visited.add(neighbor)
                queue.append(neighbor)
# DFS (재귀)
def dfs(graph, node, visited=None):
    if visited is None:
        visited = set()
    
    visited.add(node)
    print(node)
    
    for neighbor in graph[node]:
        if neighbor not in visited:
            dfs(graph, neighbor, visited)

2단계: 중요 알고리즘

동적 프로그래밍 (DP)

한 줄 요약: 큰 문제를 작은 문제의 답으로 쌓아 올립니다. “겹치는 하위 문제”가 있고, 최적 부분 구조(작은 답을 알면 큰 답을 만들 수 있음)가 성립할 때 씁니다. 피보나치 예제는 설명용이고, 시험에서는 보통 배낭, LIS, 편집 거리, 구간 합 조건 같은 형태로 나옵니다. 설계할 때는 dp[i]정확히 무엇을 의미하는지 한국어로 한 문장 적는 습관이 중요해요. “앞 i개까지 봤을 때 …”처럼요. 메모이제이션(재귀+캐시)과 바텀업(표 채우기)은 같은 수학이고, 후자가 디버깅이 쉬운 편입니다. 백트래킹은 일단 후보를 탐색하다 막히면 되돌아오는 전략이고, DP와 같이 쓰이기도(가지치기) 합니다. “모든 경우”를 다 보면 시간이 터지니, 제약이 작을 때(n ≤ 20 등) 많이 나옵니다. 다음은 python를 활용한 상세한 구현 코드입니다. 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 예제: 피보나치 수열
def fibonacci(n):
    if n <= 1:
        return n
    
    dp = [0] * (n + 1)
    dp[1] = 1
    
    for i in range(2, n + 1):
        dp[i] = dp[i-1] + dp[i-2]
    
    return dp[n]
# 시간복잡도: O(n)
# 공간복잡도: O(n)

그리디

한 줄 요약: 매 단계에서 지금 보기에 제일 좋은 선택을 하면 전체가 최적이라는 교환 논증이 있을 때만 안전합니다. 아래 동전 예제는 동전 액면이 서로 배수 관계일 때(예: 1, 5, 10, 50원) 같은 특수한 구조에서 잘 작동하는 패턴입니다. 임의의 동전 조합이면 그리디가 틀릴 수 있어요. 시험에서 그리디를 택했다면 “왜 이 순서가 맞는지”를 스스로에게 한 번 말해 보는 게 좋습니다. 안 되면 그리디가 아니라 DP나 완탐+최적화일 가능성을 의심합니다. 아래 코드는 python를 사용한 구현 예제입니다. 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 예제: 동전 거스름돈
def coin_change(coins, amount):
    coins.sort(reverse=True)
    count = 0
    
    for coin in coins:
        if amount >= coin:
            count += amount // coin
            amount %= coin
    
    return count if amount == 0 else -1

3단계: 고급 알고리즘 (가끔, 그러나 한 번 나오면 크게 다침)

여기는 매 라운드마다 필수는 아닙니다. 다만 “그래프 + 가중치”, “선행 과목/작업 순서”, “문자열을 접두어로 많이 검색” 같은 문장이 보이면 머리에 올려두면 편합니다. 최단 경로: 간선에 가중치가 있으면 다익스트라(음수 없을 때), 음수 간선이면 벨만-포드, 모든 쌍이면 플로이드-워샬 같은 선택지가 나옵니다. 코테에서는 다익스트라+우선순위 큐 조합이 제일 흔한 편입니다. “간선이 많은지 적은지”에 따라 인접 리스트를 쓰는 건 당연 전제고요. 위상 정렬: 방향 그래프에서 사이클이 없고, 선행 관계를 한 줄로 펴야 할 때 씁니다. indegree(들어오는 간선 수)를 큐로 0인 애부터 빼 내는 방식이 직관적입니다. 사이클이 있으면 모든 정점을 방문 못 하니까 그걸로 “불가능” 판정하는 문제도 많습니다. 트라이(Trie): 문자열의 접두어 공유를 트리로 표현합니다. 자동완성, 검색어 중복 제거, 비트 트라이로 XOR 최대 같은 변형문까지 이어집니다. 구현은 노드 맵이나 고정 크기 자식 배열 두 가지 흐름이 대표적이에요.

2. 필수 자료구조

자료구조는 “암기 목록”이라기보다 연산의 평균 비용을 손에 익히는 일에 가깝습니다. 코테에서 시간 초과가 나면 대부분은 알고리즘 자체보다 “이 연산이 O(n)인 줄 알았는데 O(n log n)” 같은 선택 실수에서 옵니다. 아래 표는 대략적인 출제 빈도 느낌이고, 본인이 약한 연산만 표시해 두고 문제 풀 때마다 한 번씩 짚어도 충분합니다.

우선순위별 학습

우선순위자료구조출제 빈도난이도
1배열 (Array)매우 높음쉬움
2해시맵 (HashMap)매우 높음쉬움
3스택 (Stack)높음쉬움
4큐 (Queue)높음쉬움
5힙 (Heap)중간중간
6트리 (Tree)중간중간
7그래프 (Graph)중간어려움

자료구조별 핵심 연산

배열

리스트는 “그냥 쓰는 것” 같아도, 앞쪽 삽입/삭제가 잦은지, 정렬 후 이진 탐색까지 갈지 plan을 세우면 난이도가 갈립니다. Python 리스트는 끝이 싸고 앞이 비쌉니다. C++ vector도 비슷한 감각이에요. “정렬했다가 인덱스가 필요하다”면 원본 인덱스를 pair로 들고 다니는 패턴을 한 번쯤 손으로 써 보세요. 아래 코드는 python를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

# 필수 연산
arr = [1, 2, 3, 4, 5]
arr.append(6)        # 뒤에 추가 O(1)
arr.pop()            # 뒤에서 제거 O(1)
arr.insert(0, 0)     # 앞에 추가 O(n)
arr.remove(3)        # 값 제거 O(n)
arr.sort()           # 정렬 O(n log n)

해시맵 (딕셔너리)

“값 → 빈도”, “값 → 최근 인덱스”, “필요한 보조 정보 O(1)로” 같은 문제의 기본기입니다. 키로 리스트나 커스텀 객체를 쓸 때는 해시 가능 여부(Python은 tuple은 되고 list는 안 됨)만 확인하면 됩니다. 정렬이 필요한데 dict만 맴돌면 역으로 느려질 때가 있어요. “카운트만”이면 Counter가 읽기 쉽습니다. 아래 코드는 python를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

# 필수 연산
# 실행 예제
d = {}
d['key'] = 'value'   # 삽입 O(1)
val = d.get('key')   # 조회 O(1)
del d['key']         # 삭제 O(1)
'key' in d           # 존재 확인 O(1)

스택

가장 나중에 넣은 게 먼저 나옴이 생명입니다. 괄호 짝 맞추기, 트리 DFS를 반복문으로, “되돌리기”가 있는 문제에서 자주 등장합니다. 큐와 헷갈리면 “대기줄 vs 접시 쌓기”로만 구분해도 시험장에서 덜 섞입니다. 아래 코드는 python를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

# 스택 (LIFO)
# 실행 예제
stack = []
stack.append(1)      # push
stack.append(2)
top = stack.pop()    # pop (2)

BFS의 큐는 deque가 표준입니다. 리스트로 pop(0) 하면 O(n)이라 조용히 터집니다. “먼저 들어온 게 먼저 처리”만 기억하면 되고, 우선순위가 생기는 순간 그건 큐가 아니라 문제로 넘어갑니다. 아래 코드는 python를 사용한 구현 예제입니다. 필요한 모듈을 import하고. 코드를 직접 실행해보면서 동작을 확인해보세요.

from collections import deque
# 큐 (FIFO)
queue = deque()
queue.append(1)      # enqueue
queue.append(2)
front = queue.popleft()  # dequeue (1)

힙 (우선순위 큐)

파이썬 heapq최소 힙이라 “최대값 꺼내기”는 음수 트릭이나 (우선순위, 카운트, 값) 튜플로 tie-break를 고정하는 방식이 흔합니다. 다익스트라, 중간값 유지(두 힙), 스케줄링 문제에서 부담 없이 쓰입니다. “정렬을 매번” 할 거를 힙 한 번으로 줄이는 그림인지 보면 설계가 빨라져요. 다음은 python를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

import heapq
# 최소 힙
heap = []
heapq.heappush(heap, 3)
heapq.heappush(heap, 1)
heapq.heappush(heap, 2)
min_val = heapq.heappop(heap)  # 1
# 최대 힙 (음수 사용)
max_heap = []
heapq.heappush(max_heap, -3)
heapq.heappush(max_heap, -1)
max_val = -heapq.heappop(max_heap)  # 3

트리와 그래프 (개념만 짚기)

코테에서 트리는 보통 포인터(노드 객체)로 주거나 부모 배열/인접 리스트로 줍니다. 재귀 DFS가 읽기 쉽고, 깊이가 깊으면 스택으로 바꿉니다. 그래프는 무방향/방향, 가중치 유무, 자기 루프·중복 간선만 먼저 체크해도 구현 실수가 확 줄어요.

3. 문제 풀이 패턴

아래 플로우차트는 “정답이 아니라 첫 추측”이에요. 막히면 한 단계만 내려가서 브루트포스 복잡도부터 적어 보는 게 더 빠를 때도 많습니다.

패턴 인식 플로우차트

아래 코드는 mermaid를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

flowchart TD
    A[문제 읽기] --> B{정렬된 배열?}
    B -->|예| C[이진 탐색 or 투 포인터]
    B -->|아니오| D{부분 배열/부분 문자열?}
    D -->|예| E[슬라이딩 윈도우]
    D -->|아니오| F{그래프/트리?}
    F -->|예| G[BFS/DFS]
    F -->|아니오| H{최적화 문제?}
    H -->|예| I[DP or 그리디]
    H -->|아니오| J[해시맵 or 스택/큐]

패턴별 예제

아래 LeetCode 번호는 “이런 류였지” 되살리기용입니다. 원리가 이해되면 같은 계열 사이트 문제로 옮겨도 됩니다. 패턴 1: 투 포인터 — 정렬 후 좌우를 좁혀 가며 중복·합 조건을 만족하는 튜플을 모읍니다. 고정된 i에 대해 left/right가 한 번씩만 지나가도록 짜는 게 핵심이에요. 다음은 python를 활용한 상세한 구현 코드입니다. 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# LeetCode 15. 3Sum
# 함수 정의 및 구현
def three_sum(nums):
    nums.sort()
    result = []
    
    for i in range(len(nums) - 2):
        if i > 0 and nums[i] == nums[i-1]:
            continue
        
        left, right = i + 1, len(nums) - 1
        while left < right:
            total = nums[i] + nums[left] + nums[right]
            if total == 0:
                result.append([nums[i], nums[left], nums[right]])
                left += 1
                right -= 1
                while left < right and nums[left] == nums[left-1]:
                    left += 1
            elif total < 0:
                left += 1
            else:
                right -= 1
    
    return result

패턴 2: 슬라이딩 윈도우 — 오른쪽을 전진시키면서 조건을 깨면 왼쪽을 당깁니다. set 대신 카운터 딕셔너리로 바꾸는 변형이 더 자주 나옵니다(문자 빈도 제한 문제). 다음은 python를 활용한 상세한 구현 코드입니다. 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# LeetCode 3. Longest Substring Without Repeating Characters
def length_of_longest_substring(s):
    char_set = set()
    left = 0
    max_length = 0
    
    for right in range(len(s)):
        while s[right] in char_set:
            char_set.remove(s[left])
            left += 1
        
        char_set.add(s[right])
        max_length = max(max_length, right - left + 1)
    
    return max_length

패턴 3: BFS (레벨 순회) — 큐에서 한 레벨씩 level_size로 묶으면 “깊이별 결과”를 바로 얻습니다. 최단 거리(가중치 1) 문제에서도 같은 그림이 반복됩니다. 다음은 python를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# LeetCode 102. Binary Tree Level Order Traversal
from collections import deque
def level_order(root):
    if not root:
        return []
    
    result = []
    queue = deque([root])
    
    while queue:
        level_size = len(queue)
        level = []
        
        for _ in range(level_size):
            node = queue.popleft()
            level.append(node.val)
            
            if node.left:
                queue.append(node.left)
            if node.right:
                queue.append(node.right)
        
        result.append(level)
    
    return result

4. 시간 관리

시간 배분표는 사람마다 체감이 달라서, 숫자보다 “막히면 바로 다음으로” 같은 규칙을 하나 정해 두는 편이 실전에 도움이 됩니다. 아래 표는 4문제짜리 2시간 전형을 가정한 예시입니다.

시험 시간 배분 (2시간, 4문제 기준)

아래 코드는 text를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

총 시간: 120분
문제 1 (Easy):   20분
문제 2 (Medium): 30분
문제 3 (Medium): 35분
문제 4 (Hard):   35분
예비 시간: 10분 (검토 및 디버깅)

문제 풀이 프로세스

아래 코드는 mermaid를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

flowchart LR
    A[문제 읽기 3분] --> B[예제 분석 2분]
    B --> C[접근법 설계 5분]
    C --> D[코드 작성 15분]
    D --> E[테스트 3분]
    E --> F[디버깅 2분]

각 단계별 체크리스트: 1. 문제 읽기 (3분):

  • 입력 형식 확인
  • 출력 형식 확인
  • 제약 조건 확인 (n의 범위, 시간 제한)
  • 엣지 케이스 파악 2. 예제 분석 (2분):
  • 예제 입력/출력 손으로 따라가기
  • 패턴 인식
  • 예외 케이스 생각 3. 접근법 설계 (5분):
  • 브루트포스 시간복잡도 계산
  • 최적화 방법 고민
  • 자료구조 선택
  • 슈도코드 작성 4. 코드 작성 (15분):
  • 함수 시그니처 작성
  • 핵심 로직 구현
  • 엣지 케이스 처리 5. 테스트 (3분):
  • 예제 입력으로 테스트
  • 엣지 케이스 테스트 (빈 배열, 크기 1, 최대 크기)
  • 출력 형식 확인 6. 디버깅 (2분):
  • 에러 메시지 확인
  • print 디버깅
  • 논리 오류 수정

5. 언어 선택

언어는 “정답이 하나”가 아니라 손에 익은 쪽이 이깁니다. Python으로만 연습했는데 시험이 C++만 허용이면 당연히 불리하고, 반대로 회사 스택이 Java면 IDE 자동완성에 익숙한 쪽이 유리할 수도 있어요. 아래 표는 대략적인 성향만 보고, 마지막 한 달은 실제 시험과 같은 환경으로 맞추는 게 좋습니다.

언어별 장단점

언어장점단점추천 대상
Python간결한 문법, 빠른 구현느린 속도 (TLE 가능)대부분의 경우
C++빠른 속도, STL긴 코드, 디버깅 어려움성능 중요 문제
Java안정적, 풍부한 API장황한 문법엔터프라이즈 배경
JavaScript웹 개발자 친숙타입 안전성 부족웹 개발자

Python 추천 이유

1. 간결한 문법: 아래 코드는 python를 사용한 구현 예제입니다. 필요한 모듈을 import하고, 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# Python (5줄)
def reverse_string(s):
    return s[::-1]
# C++ (10줄)
#include <string>
#include <algorithm>
string reverseString(string s) {
    reverse(s.begin(), s.end());
    return s;
}

2. 풍부한 내장 함수: 아래 코드는 python를 사용한 구현 예제입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 정렬
arr.sort()
# 최대/최소
max_val = max(arr)
min_val = min(arr)
# 합계
total = sum(arr)
# 카운트
from collections import Counter
count = Counter(arr)

3. 슬라이싱: 다음은 간단한 python 코드 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

arr = [1, 2, 3, 4, 5]
arr[1:4]    # [2, 3, 4]
arr[::-1]   # [5, 4, 3, 2, 1] (역순)
arr[::2]    # [1, 3, 5] (2칸씩)

C++ 사용 시기

TLE (Time Limit Exceeded) 발생 시: 아래 코드는 text를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

문제 제약: n ≤ 10^6, 시간 제한 1초
Python: 10^6 연산 → 1초 (아슬아슬)
C++:    10^6 연산 → 0.1초 (여유)
→ Python으로 풀다가 TLE 나면 C++로 전환

6. 실전 팁

여기서부터는 “알고리즘”이라기보다 시험 볼 때 신경 덜 쓰게 만드는 습관에 가깝습니다. 입력/출력 템플릿은 손이 기억하게 만들고, 복잡도 표는 n 범위만 봐도 대충 감이 오게 붙여 두세요.

팁 1: 템플릿 준비

Python 템플릿: 아래 코드는 python를 사용한 구현 예제입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 입력 처리
n = int(input())
arr = list(map(int, input().split()))
# 또는
import sys
input = sys.stdin.readline
# 출력
print(result)

C++ 템플릿: 다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int n;
    cin >> n;
    
    vector<int> arr(n);
    for (int i = 0; i < n; i++) {
        cin >> arr[i];
    }
    
    // 로직
    
    cout << result << endl;
    
    return 0;
}

팁 2: 시간복잡도 체크

아래 코드는 text를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

n의 범위로 시간복잡도 추정:
n ≤ 10:        O(n!) 가능
n ≤ 20:        O(2^n) 가능
n ≤ 100:       O(n³) 가능
n ≤ 1,000:     O(n²) 가능
n ≤ 10,000:    O(n² / 2) 가능
n ≤ 100,000:   O(n log n) 필요
n ≤ 1,000,000: O(n) 필요
n > 1,000,000: O(log n) 또는 O(1) 필요

팁 3: 디버깅 전략

아래 코드는 python를 사용한 구현 예제입니다. 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# print 디버깅
def solve(arr):
    print(f"DEBUG: arr = {arr}")  # 입력 확인
    
    result = []
    for i in range(len(arr)):
        print(f"DEBUG: i = {i}, arr[i] = {arr[i]}")  # 중간 과정
        result.append(arr[i] * 2)
    
    print(f"DEBUG: result = {result}")  # 출력 확인
    return result

팁 4: 엣지 케이스 체크

아래 코드는 python를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 항상 테스트해야 할 케이스
test_cases = [
    [],              # 빈 배열
    [1],             # 크기 1
    [1, 1, 1],       # 모두 같은 값
    [1, 2, 3],       # 정렬된 배열
    [3, 2, 1],       # 역순
    [-1, 0, 1],      # 음수 포함
    [10**9],         # 최대값
]

7. 정리

3개월 학습 플랜

1개월차: 기초 다지기

  • 배열, 해시맵, 스택, 큐
  • 투 포인터, 슬라이딩 윈도우
  • LeetCode Easy 50문제 2개월차: 중급 알고리즘
  • BFS/DFS, 이진 탐색
  • 동적 프로그래밍 기초
  • LeetCode Medium 50문제 3개월차: 고급 알고리즘
  • 동적 프로그래밍 고급
  • 그래프 알고리즘
  • LeetCode Medium 50문제 + Hard 20문제

학습 자료

온라인 저지:

  • LeetCode - 글로벌 표준
  • 백준 - 한국 최대
  • 프로그래머스 - 기업 코딩 테스트 추천 문제집:
  • LeetCode Top 100 Liked
  • LeetCode Blind 75
  • 백준 단계별로 풀어보기

다음 단계

같은 사이트에서 풀이를 더 깊게 보고 싶다면 아래를 순서 없이 골라도 됩니다. 번호가 작다고 쉬운 건 아니니, 목차만 보고 필요한 조각부터 열어도 괜찮아요.

... 996 lines not shown ... Token usage: 63706/1000000; 936294 remaining Start-Sleep -Seconds 3