Skip to Content
WebJavaScriptJavaScript 코딩테스트02. 시간복잡도와 자료구조 선택 기준

이번 편의 결과물: (코드 산출물 없음) Big-O 표기법과 문제 유형별 자료구조 선택 기준을 정리하고, 03편부터 모든 solution.js 상단에 쓸 복잡도 주석 규칙을 정합니다. · 다루는 개념: Big-O 표기법, 시간·공간 복잡도 트레이드오프, 문제 유형 → 자료구조 선택 지도

이 편에서 만드는 파일

이 편은 이론 편이라 coding-test/에 새 폴더를 만들지 않습니다. 대신 03편부터 모든 문제 풀이에 적용할 복잡도 주석 규칙을 이 편에서 정합니다.

개념 정리

Big-O 표기법이란

Big-O(빅오)는 입력 크기 n이 커질 때 실행 시간(또는 메모리)이 늘어나는 정도만 표현하는 표기법입니다. 상수 배와 낮은 차수 항은 무시하고, 가장 크게 영향을 주는 항만 남깁니다. 예를 들어 실제 연산 횟수가 3n + 5여도 n이 아주 커지면 +5와 계수 3은 상대적으로 무의미해지므로 O(n)으로 표기합니다.

자주 등장하는 차수

표기이름n=10일 때 대략 연산 수n=1000일 때 대략 연산 수
O(1)상수11
O(log n)로그310
O(n)선형101000
O(n log n)선형 로그339966
O(n^2)이차1001000000
O(2^n)지수1024계산 불가능한 규모

n이 10에서 1000으로 100배 늘어날 때 O(n)은 100배만 늘어나지만 O(n^2)는 10000배로 늘어납니다. 코딩테스트에서 시간 제한을 지키려면 문제의 입력 크기를 보고 어떤 차수까지 허용되는지 먼저 가늠해야 합니다. 예를 들어 n이 100000 규모면 O(n^2)는 대개 시간 초과이고 O(n log n) 이하가 필요합니다.

시간·공간 트레이드오프

같은 문제를 시간을 더 쓰고 공간을 아끼거나, 공간을 더 쓰고 시간을 아끼는 두 방향으로 풀 수 있습니다. “배열에 중복된 값이 있는지 확인”하는 문제로 비교합니다.

방법시간복잡도공간복잡도설명
이중 반복문으로 모든 쌍 비교O(n^2)O(1)추가 메모리는 안 쓰지만 느리다
Set에 값을 담으며 이미 있는지 확인O(n)O(n)메모리를 더 쓰지만 훨씬 빠르다

04편에서 Map과 Set으로 조회를 O(1)에 가깝게 만드는 이유가 바로 이 트레이드오프입니다. 메모리가 넉넉한 코딩테스트 환경에서는 대체로 시간을 아끼는 쪽을 선택합니다.

문제 유형 → 자료구조 선택 지도

문제에서 필요한 동작적합한 자료구조관련 편
값의 존재·중복 여부를 빠르게 확인Map, Set04
마지막에 넣은 것을 먼저 꺼냄(LIFO), 괄호 짝 확인스택05
먼저 넣은 것을 먼저 꺼냄(FIFO), 순서대로 처리05
정렬된 데이터에서 조건을 만족하는 지점 찾기이분 탐색07
최솟값(또는 최댓값)을 반복해서 꺼내야 함12
노드와 간선으로 이루어진 연결 관계 탐색그래프(인접 리스트)10, 11
부분 문제의 답을 저장해 재활용DP 테이블(배열, Map)13

이 표는 문제를 처음 읽었을 때 “어떤 자료구조로 접근할지” 판단하는 출발점입니다. 실제로는 여러 자료구조를 함께 쓰는 문제도 많습니다.

복잡도 주석 규칙(03편부터 모든 solution.js에 적용)

앞으로 모든 solution.js는 파일 경로 주석 다음 줄에 시간·공간 복잡도를 이유와 함께 적습니다.

// coding-test/03-arrays-and-strings/01-example/solution.js // 시간복잡도: O(n) — 배열을 한 번 순회하며 합을 구한다 // 공간복잡도: O(1) — 입력 외 추가 메모리를 쓰지 않는다 export function solution(nums) { // ... }

시간복잡도공간복잡도 뒤에는 항상 표기법과 그 근거를 한 문장으로 씁니다. 근거 없이 표기법만 적으면 나중에 왜 그 복잡도인지 스스로도 설명하기 어려워집니다.

실습

터미널에서 복잡도 차이를 직접 체감합니다. 이 실험은 coding-test/ 저장소에 저장하지 않고 임시로 실행만 합니다.

1. O(n) 코드의 실행 시간 측정

node -e "const n = 20000000; console.time('linear'); let sum = 0; for (let i = 0; i < n; i++) { sum += i; } console.timeEnd('linear');"

2. O(n^2) 코드의 실행 시간 측정

같은 n으로 이중 반복문을 돌립니다. n이 크면 매우 오래 걸리므로 훨씬 작은 값(4000)으로 줄여서 실행합니다.

node -e "const n = 4000; console.time('quadratic'); let count = 0; for (let i = 0; i < n; i++) { for (let j = 0; j < n; j++) { count++; } } console.timeEnd('quadratic');"

3. n을 2배로 늘려 다시 측정

1번은 n을 2배(4000만), 2번은 n을 2배(8000)로 늘려 각각 다시 실행하고 실행 시간이 몇 배로 늘어나는지 비교합니다.

확인

  • O(n) 코드는 n을 2배로 늘려도 실행 시간이 대략 2배 정도로만 늘어납니다.
  • O(n^2) 코드는 n을 2배로 늘리면 실행 시간이 대략 4배로 늘어납니다(반복 횟수가 n * n이므로).
  • 두 결과를 비교해 “차수가 높을수록 입력이 커질 때 훨씬 불리해진다”는 것을 실행 시간으로 확인합니다.

직접 해보기

  1. O(n log n)에 해당하는 코드로 Array.prototype.sort()를 큰 배열에 적용해보고, n을 2배로 늘렸을 때 실행 시간이 O(n)보다는 많이, O(n^2)보다는 적게 늘어나는지 확인해봅니다.
  2. 문제 유형 → 자료구조 선택 지도 표를 보지 않고, “값이 중복 없이 존재하는지 빠르게 확인하는 문제”에 어떤 자료구조가 적합할지 먼저 답해본 뒤 표와 비교해봅니다.

정답 보기(2번)

Map 또는 Set이 적합합니다. 두 자료구조 모두 평균적으로 O(1)에 값의 존재 여부를 확인할 수 있어, 배열을 매번 처음부터 훑는 O(n) 방식보다 반복 조회가 많은 문제에서 유리합니다.

자주 하는 실수

오해실제
Big-O는 정확한 실행 시간(초 단위)을 알려준다Big-O는 입력이 커질 때 “늘어나는 정도”만 나타낸다. 실제 시간은 하드웨어·상수에 따라 다르다
반복문이 하나면 항상 O(n)이다반복문 안에서 배열 검색(includes 등)처럼 또 다른 O(n) 작업을 하면 전체는 O(n^2)가 될 수 있다
공간복잡도는 항상 무시해도 된다입력 크기가 매우 크면 O(n) 공간도 메모리 제한에 걸릴 수 있어 함께 고려해야 한다

확인 문제

문제 14지선다
Big-O 표기법이 나타내는 것으로 가장 정확한 것은?
문제 24지선다
반복문 하나만 있어도 전체 복잡도가 O(n^2)가 될 수 있는 경우는?
문제 34지선다
값의 중복 여부를 여러 번 빠르게 확인해야 하는 문제에 시간·공간 트레이드오프 관점에서 적합한 선택은?
문제 44지선다
n이 100에서 1000으로 10배 늘었을 때 실행 시간이 이론상 약 100배로 늘어나는 복잡도는?

참고 자료

Last updated on