개발자 취업을 위한 알고리즘 수학 핵심 요약
코딩 테스트를 준비하는 많은 개발자들이 알고리즘 문제를 풀다가 수학적 벽에 부딪히는 경험을 합니다. 단순히 코드를 짤 줄 아는 것만으로는 부족하며, 문제의 수학적 구조를 파악하는 능력이 합격과 불합격을 가르는 핵심 역량입니다. 카카오, 네이버, 삼성 등 주요 기업의 코딩 테스트에서는 수학적 사고를 요구하는 문제가 꾸준히 출제되고 있습니다.
수학이 필요한 가장 근본적인 이유는 효율성입니다. 같은 문제를 브루트포스로 풀면 시간 초과가 나지만, 수학 공식을 적용하면 O(1)이나 O(log n)에 해결할 수 있는 경우가 많습니다. 예를 들어, 1부터 n까지의 합을 반복문으로 구하면 O(n)이지만, n(n+1)/2 공식을 쓰면 O(1)입니다.
알고리즘의 성능을 수학적으로 표현하는 Big-O 표기법은 코딩 테스트의 기본 언어입니다. 입력 크기 n이 커질 때 연산 횟수가 어떻게 증가하는지를 나타냅니다. 핵심은 최고차항만 남기고 계수를 무시하는 것입니다. 3n² + 5n + 10은 O(n²)이 됩니다.
코딩 테스트에서 시간 제한은 보통 1~2초입니다. 1초에 약 1억 번의 연산이 가능하다고 가정하면, 입력 크기 n이 100,000일 때 O(n²)은 100억 번으로 시간 초과, O(n log n)은 약 170만 번으로 통과합니다. 문제를 읽자마자 입력 크기를 확인하고, 허용 가능한 시간 복잡도를 역산하는 습관이 중요합니다.
코딩 테스트에서 반복적으로 등장하는 수학 공식들이 있습니다. 이 공식들을 코드로 구현할 수 있어야 하며, 어떤 상황에서 적용해야 하는지 판단하는 능력이 필요합니다.
순열(Permutation)은 n개에서 r개를 뽑아 순서대로 나열하는 경우의 수입니다. nPr = n! / (n-r)!로 계산합니다. 조합(Combination)은 순서를 고려하지 않고 r개를 선택하는 경우의 수이며, nCr = n! / (r! × (n-r)!)입니다. 코딩 테스트에서는 경우의 수 문제, 확률 문제, 부분집합 문제 등에 광범위하게 사용됩니다. 큰 수에 대해서는 모듈러 연산(mod 1,000,000,007)과 함께 사용하는 것이 일반적입니다.
유클리드 호제법은 두 수의 최대공약수(GCD)를 효율적으로 구하는 알고리즘입니다. GCD(a, b) = GCD(b, a % b)를 재귀적으로 적용하며, b가 0이 되면 a가 GCD입니다. 최소공배수(LCM)는 LCM(a, b) = a × b / GCD(a, b)로 구합니다. 분수 계산, 주기 문제, 타일링 문제 등에서 자주 출제됩니다.
n 이하의 모든 소수를 구할 때 가장 효율적인 방법이 에라토스테네스의 체입니다. 2부터 시작하여 각 소수의 배수를 순서대로 지워나가는 방식으로, 시간 복잡도는 O(n log log n)입니다. 단일 소수 판별은 2부터 √n까지만 나누어보면 O(√n)에 확인할 수 있습니다. 소수 관련 문제는 코딩 테스트 단골 주제입니다.
aⁿ을 구할 때 단순 반복은 O(n)이지만, 분할 정복을 이용한 빠른 거듭제곱은 O(log n)에 계산합니다. 핵심 아이디어는 aⁿ = (a^(n/2))² (n이 짝수), aⁿ = a × a^(n-1) (n이 홀수)입니다. 큰 수의 모듈러 거듭제곱 연산에 필수적이며, 행렬 거듭제곱과 결합하면 피보나치 수열도 O(log n)에 구할 수 있습니다.
F(n) = F(n-1) + F(n-2)로 정의되는 피보나치 수열은 동적 프로그래밍의 대표 예제이자 다양한 응용 문제의 기반입니다. 단순 재귀는 O(2ⁿ), 메모이제이션을 적용하면 O(n), 행렬 거듭제곱을 사용하면 O(log n)에 계산할 수 있습니다. 계단 오르기, 타일링, 경로 수 계산 등 많은 문제가 피보나치 변형입니다.
그래프는 코딩 테스트에서 가장 자주 출제되는 자료구조 중 하나입니다. 노드(정점)와 엣지(간선)로 구성되며, 네트워크, 경로 탐색, 관계 모델링 등 다양한 문제를 표현할 수 있습니다. 그래프 문제를 풀기 위해서는 탐색 알고리즘과 최적화 기법에 대한 이해가 반드시 필요합니다.
인접 행렬은 n×n 2차원 배열로 간선의 존재를 표현합니다. 두 노드 간 연결 여부를 O(1)에 확인할 수 있지만, 공간 복잡도가 O(n²)입니다. 인접 리스트는 각 노드에 연결된 노드 목록을 저장합니다. 공간 복잡도가 O(V+E)로 효율적이며, 대부분의 코딩 테스트에서 인접 리스트를 사용합니다. 노드 수가 많고 간선이 적은 희소 그래프에서는 인접 리스트가 압도적으로 유리합니다.
너비 우선 탐색(BFS)은 큐를 사용하여 가까운 노드부터 탐색합니다. 최단 경로, 레벨별 탐색, 연결 요소 찾기에 적합합니다. 깊이 우선 탐색(DFS)은 스택 또는 재귀를 사용하여 한 방향으로 끝까지 탐색합니다. 경로 탐색, 사이클 감지, 위상 정렬에 활용됩니다. 두 알고리즘 모두 시간 복잡도는 O(V+E)이며, 문제 유형에 따라 적절한 탐색 방법을 선택해야 합니다.
다익스트라(Dijkstra) 알고리즘은 가중치가 있는 그래프에서 한 노드로부터 다른 모든 노드까지의 최단 거리를 구합니다. 우선순위 큐(힙)를 사용하면 O(E log V)의 시간 복잡도로 동작합니다. 음의 가중치가 없는 그래프에서만 사용할 수 있으며, 음의 가중치가 있으면 벨만-포드 알고리즘을 사용해야 합니다.
그래프의 모든 노드를 연결하면서 간선 가중치의 합을 최소로 만드는 트리입니다. 크루스칼 알고리즘은 간선을 가중치 순으로 정렬한 뒤 사이클이 생기지 않도록 선택하며, Union-Find 자료구조를 활용합니다. 프림 알고리즘은 임의의 노드에서 시작하여 인접한 간선 중 최소 가중치를 선택해 확장합니다. 네트워크 설계, 도로 건설 비용 최소화 등의 문제에 출제됩니다.
동적 프로그래밍(DP)은 코딩 테스트에서 가장 어렵지만 가장 많이 출제되는 유형입니다. DP의 핵심은 큰 문제를 작은 부분 문제로 나누고, 부분 문제의 답을 저장하여 중복 계산을 피하는 것입니다. 수학적으로는 점화식(재귀 관계식)을 세우는 것이 가장 중요한 단계입니다.
DP 문제를 풀기 위한 첫 번째 단계는 상태를 정의하고 점화식을 세우는 것입니다. dp[i]가 무엇을 의미하는지 명확히 정의한 후, dp[i]를 이전 상태(dp[i-1], dp[i-2] 등)로 표현하는 관계식을 도출합니다. 예를 들어, 계단 오르기 문제에서 dp[i] = dp[i-1] + dp[i-2]이고, 배낭 문제에서는 dp[i][w] = max(dp[i-1][w], dp[i-1][w-w_i] + v_i)입니다.
메모이제이션(Top-Down)은 재귀 함수에서 이미 계산한 결과를 캐시에 저장하여 재활용하는 방식입니다. 구현이 직관적이지만 재귀 깊이 제한에 주의해야 합니다. 타뷸레이션(Bottom-Up)은 반복문으로 작은 부분 문제부터 순서대로 채워나가는 방식입니다. 재귀 호출 오버헤드가 없어 일반적으로 더 효율적이며, 코딩 테스트에서 권장되는 방식입니다.
DP가 적용되려면 최적 부분 구조(Optimal Substructure)와 중복 부분 문제(Overlapping Subproblems) 두 조건을 만족해야 합니다. 최적 부분 구조란 전체 문제의 최적해가 부분 문제의 최적해로 구성될 수 있다는 성질입니다. 이 성질이 성립하지 않으면 그리디 알고리즘이나 다른 접근법을 고려해야 합니다.
코딩 테스트에서 자주 나오는 DP 유형을 정리하면 다음과 같습니다. LIS(최장 증가 부분 수열)는 O(n log n)에 풀 수 있습니다. LCS(최장 공통 부분 수열)는 두 문자열을 비교하는 2차원 DP입니다. 배낭 문제(Knapsack)는 무게 제한 내에서 가치를 최대화합니다. 구간 DP는 행렬 곱셈 순서 최적화 등에 사용됩니다. 각 유형의 점화식 패턴을 익혀두면 새로운 문제에도 빠르게 적용할 수 있습니다.
비트 연산은 정수의 이진 표현을 직접 조작하는 연산으로, 코딩 테스트에서 효율적인 상태 관리와 최적화에 핵심적으로 사용됩니다. 비트 연산에 익숙해지면 메모리를 절약하면서도 빠른 연산이 가능합니다.
비트마스킹은 정수의 각 비트를 하나의 원소로 간주하여 집합을 표현하는 기법입니다. n개의 원소가 있을 때, 0부터 2ⁿ-1까지의 정수로 모든 부분집합을 표현할 수 있습니다. 외판원 문제(TSP), 집합 커버 문제 등에서 방문한 노드 집합을 비트마스크로 관리하면 dp[mask][node] 형태의 상태 정의가 가능합니다. 부분집합 열거는 for 루프로 0부터 (1 << n) - 1까지 순회하면 됩니다.
여러 불리언 상태를 하나의 정수에 비트로 압축하면 메모리를 크게 절약할 수 있습니다. 예를 들어, 26개 알파벳의 사용 여부를 boolean 배열 대신 하나의 정수로 관리하면 비교 연산이 O(1)에 가능합니다. 게임 개발에서 캐릭터 상태(무적, 독, 화상, 둔화 등)를 비트 플래그로 관리하거나, 권한 시스템에서 읽기/쓰기/실행 권한을 비트로 표현하는 것이 대표적인 실무 활용 사례입니다.
코딩 테스트에서 수학 문제를 빠르게 풀려면 공식을 아는 것만으로는 부족합니다. 반복 연습을 통해 공식이 자동으로 떠오르는 수준까지 체화해야 합니다. VOCAB RUSH는 이 과정을 게임처럼 재미있게 만들어줍니다.
VOCAB RUSH는 프로그래밍과 알고리즘에 필요한 수학을 12개 카테고리로 체계적으로 다룹니다. 사칙연산, 분수와 소수, 거듭제곱과 제곱근, 단위 변환, 비율과 백분율, 진법 변환, 비트 연산, 논리 연산, 집합과 확률, 통계 기초, 시간 복잡도, AI 수학까지 코딩 테스트에 필요한 수학 영역을 빠짐없이 포함하고 있습니다.
VOCAB RUSH의 수학 모드는 매번 새로운 문제를 자동 생성합니다. 같은 유형이라도 숫자와 조건이 달라지기 때문에 답을 외울 수 없으며, 진짜 계산 능력과 수학적 사고력이 길러집니다. 제한 시간 내에 빠르게 풀어야 하는 방식이므로, 실전 코딩 테스트에서 수학 관련 문제를 만났을 때 계산 시간을 크게 줄일 수 있습니다. 매일 꾸준히 연습하면 복잡한 수식도 직관적으로 풀 수 있는 감각이 생깁니다.