Language/JavaScript

JavaScript 코딩테스트 대비 정리 (레벨 5)

Kun Woo Kim 2025. 8. 4. 17:21
728x90

레벨 5는 알고리즘 문제 풀이에서 가장 높은 난이도를 가진 단계입니다. 복잡한 자료구조와 고급 최적화 기법을 자바스크립트로 구현할 수 있어야 하며, 성능과 메모리 효율을 고려한 코드 작성 능력이 요구됩니다.

🧠 핵심 주제

1. 메모이제이션 (Memoization)

중복 계산을 피하기 위한 값 저장 기법입니다.

const memo = {};
function fib(n) {
  if (n < 2) return n;
  if (memo[n] !== undefined) return memo[n];
  memo[n] = fib(n - 1) + fib(n - 2);
  return memo[n];
}

DFS + DP 유형에서도 자주 사용됩니다. 키로 (node, step) 형태의 값을 Map에 저장해 중복 탐색을 방지합니다.


2. 캐싱

입력이 동일한 연산 결과를 저장합니다. 메모이제이션과 유사하나 범용적입니다.

const cache = new Map();
function expensiveFn(x) {
  if (cache.has(x)) return cache.get(x);
  const result = complexCalculation(x);
  cache.set(x, result);
  return result;
}

3. 동적 프로그래밍 최적화

- 1차원 배열로 메모리 절약

// 0/1 배낭 문제 1D DP
const dp = Array(W + 1).fill(0);
for (let i = 0; i < N; i++) {
  for (let w = W; w >= weights[i]; w--) {
    dp[w] = Math.max(dp[w], dp[w - weights[i]] + values[i]);
  }
}

- 비트 마스크 + DP

2^N 상태에 대해 메모이제이션 + DFS를 조합한 방식입니다.


🏗️ 고급 자료구조

Trie

class TrieNode {
  constructor() {
    this.children = {};
    this.isEnd = false;
  }
}

Union-Find (Disjoint Set)

const parent = Array(n+1).fill().map((_, i) => i);
function find(x) {
  if (parent[x] === x) return x;
  return parent[x] = find(parent[x]);
}
function union(a, b) {
  const rootA = find(a), rootB = find(b);
  if (rootA !== rootB) parent[rootB] = rootA;
}

세그먼트 트리 (Segment Tree)

function build(arr, node, start, end) {
  if (start === end) {
    tree[node] = arr[start];
  } else {
    const mid = Math.floor((start + end) / 2);
    build(arr, 2*node, start, mid);
    build(arr, 2*node+1, mid+1, end);
    tree[node] = tree[2*node] + tree[2*node+1];
  }
}

깊은 재귀에 주의. 입력 10^5 이상이면 JS에서 성능 저하 발생 가능.


🔁 함수형 스타일 활용

const newArr = arr.map(x => x * 2).filter(x => x % 3 === 0);

함수형 스타일은 불변성을 유지하고, 부작용을 최소화하지만, 메모리와 성능에 영향이 있을 수 있습니다.


⚙️ 알고리즘 성능 최적화

  • Big-O 줄이기: O(N^2) → O(N log N) 또는 O(N)
  • 정렬 + 투 포인터, Map 활용
  • 사전 계산 (에라토스테네스의 체 등)
const isPrime = Array(1000001).fill(true);
isPrime[0] = isPrime[1] = false;
for (let i = 2; i * i <= 1000000; i++) {
  if (isPrime[i]) {
    for (let j = i * i; j <= 1000000; j += i) {
      isPrime[j] = false;
    }
  }
}

🧪 테스트 & 디버깅

  • console.time() / console.timeEnd()으로 시간 측정
  • 작은 테스트 케이스로 검증 반복
  • 경계 조건 확인 (배열 범위, DP 초기값 등)

✅ 최종 팁 요약

  • 재귀 깊이, 객체 참조 등 JS 한계 인식
  • 불필요한 루프 안 연산 제거
  • 캐시, Map 적극 활용
  • 정렬 + 이분탐색, 슬라이딩 윈도우, 해시 맵 등의 기법 숙지
  • 최종 제출 전 입력 크기 기준 시간복잡도 반드시 계산

JavaScript는 자료구조 라이브러리가 부족하지만, 다양한 구현력과 최적화 전략으로 고난이도 문제도 충분히 해결할 수 있습니다. 꾸준한 연습과 사고력 확장을 통해 실전 코딩테스트를 정복합시다 💪

728x90