1. 🧠 동적 계획법 (Dynamic Programming, DP)
개념
- 복잡한 문제를 작은 하위 문제로 나누어 풀고, 결과를 저장해 재사용
- 조건: 최적 부분 구조, 중복 부분 문제
구현 방식
- Top-down: 재귀 + 메모이제이션
- Bottom-up: 반복문으로 작은 문제부터 해결
예시 (피보나치 Bottom-up)
int Fibonacci(int n) {
int[] dp = new int[n + 1];
dp[0] = 0; dp[1] = 1;
for (int i = 2; i <= n; i++)
dp[i] = dp[i - 1] + dp[i - 2];
return dp[n];
}
대표 문제
피보나치 수열, 계단 오르기, 최소 동전, LCS, 배낭 문제
중복되는 하위 문제를 저장해 재활용하며 푸는 방법
→ 비효율적인 재귀 호출을 피하고 성능을 극대화함.
📌 대표 예시: 피보나치 수열, 계단 오르기, 최소 비용 문제
"같은 계산을 두 번 하지 않는다!"
2. 🪙 그리디 알고리즘 (Greedy)
개념
- 매 순간 최적의 선택을 하는 알고리즘
- 전체 최적을 보장하려면 특정 조건을 만족해야 함
예시 (동전 거스름돈)
int CoinChange(int[] coins, int target) {
Array.Sort(coins); Array.Reverse(coins);
int count = 0;
foreach (int coin in coins) {
count += target / coin;
target %= coin;
}
return count;
}
대표 문제
동전 교환, 회의실 배정, 활동 선택, 최소 스패닝 트리
매 순간 가장 최적인 선택을 하는 방식
→ 전체 최적해가 보장되지는 않지만, 특정 조건에서는 매우 빠르고 정확함.
📌 대표 예시: 동전 거스름돈, 회의실 배정, 최소 회의 수
"지금 가장 좋은 걸 고르자!"
3. ⚔️ 분할 정복 (Divide and Conquer)
개념
- 문제를 작게 나누고, 각각 해결, 결과를 합쳐서 해결
예시 (이진 탐색)
int BinarySearch(int[] arr, int target) {
int left = 0, right = arr.Length - 1;
while (left <= right) {
int mid = (left + right) / 2;
if (arr[mid] == target) return mid;
if (arr[mid] < target) left = mid + 1;
else right = mid - 1;
}
return -1;
}
대표 문제
병합 정렬, 퀵 정렬, 이진 탐색, 거듭제곱, Karatsuba 곱셈
문제를 작게 나누고 → 각각 해결하고 → 다시 합쳐서 해결
→ 정렬, 탐색 등 대규모 데이터를 다룰 때 성능이 뛰어남.
📌 대표 예시: 퀵 정렬, 병합 정렬, 이진 탐색
"쪼개서 풀고, 다시 합쳐서 해결한다!"
4. 🔙 백트래킹 (Backtracking)
개념
- 모든 경우의 수 탐색 + 유망하지 않으면 가지치기
- DFS 기반 + 조건 검증
대표 문제
N-Queen, 스도쿠, 미로 찾기, 조합/순열 생성
모든 경우의 수를 탐색하지만, 유망하지 않으면 미리 포기(가지치기)
→ 순열/조합, 퍼즐, N-Queen 등에서 강력한 기법.
📌 대표 예시: N-Queen, 스도쿠, 조합 만들기
"정답이 아닐 것 같으면 일찍 그만두자!"
5. 🔗 유니온-파인드 (Disjoint Set / Union-Find)
개념
- 여러 노드가 같은 집합인지 판별하거나 병합
- 주로 그래프 사이클 탐지나 네트워크 연결에 사용
예시
int Find(int[] parent, int x) {
if (parent[x] != x) parent[x] = Find(parent, parent[x]);
return parent[x];
}
void Union(int[] parent, int a, int b) {
int rootA = Find(parent, a);
int rootB = Find(parent, b);
if (rootA != rootB) parent[rootB] = rootA;
}
여러 노드가 같은 그룹인지 빠르게 확인하고 병합하는 구조
→ 네트워크 연결, 사이클 여부 확인 등에 사용됨.
📌 대표 예시: 친구 네트워크, 그래프 사이클 판별
"넌 누구랑 같은 팀이니?"
6. 🌲 트리 탐색 (DFS / BFS)
DFS
void DFS(int node, bool[] visited, List<int>[] graph) {
visited[node] = true;
foreach (var next in graph[node])
if (!visited[next]) DFS(next, visited, graph);
}
BFS
void BFS(int start, List<int>[] graph) {
var visited = new bool[graph.Length];
var q = new Queue<int>();
visited[start] = true; q.Enqueue(start);
while (q.Count > 0) {
int node = q.Dequeue();
foreach (var next in graph[node])
if (!visited[next]) { visited[next] = true; q.Enqueue(next); }
}
}
DFS: 깊이 우선 탐색 – 한 갈래로 끝까지 파고드는 방식
BFS: 너비 우선 탐색 – 가까운 노드부터 차례로 탐색
📌 대표 예시: 미로 탐색, 경로 유무 확인, 거리 계산
DFS: "끝까지 가보고 안 되면 돌아온다"
BFS: "가까운 것부터 차례로 살핀다"
7. 🚉 최단 경로 알고리즘
📍 다익스트라 (Dijkstra)
- 양수 가중치 그래프의 최단 경로
- 우선순위 큐 사용 시: O(E log V)
📍 벨만-포드 (Bellman-Ford)
- 음수 가중치 허용, 음수 사이클 탐지 가능
- 시간 복잡도: O(V × E)
📍 플로이드-워셜 (Floyd-Warshall)
- 모든 정점 쌍 간 최단 거리
- DP 기반, 시간 복잡도: O(V³)
✅ 마무리 표 (한눈에 보기)
알고리즘 |
핵심 특징 |
주 용도 |
DP |
중복 문제 + 저장 |
피보나치, 배낭, 최단거리 등 |
그리디 |
현재 최선 선택 |
동전, 회의, 최소 경로 |
분할 정복 |
분해 → 해결 → 결합 |
정렬, 탐색 |
백트래킹 |
DFS + 가지치기 |
N-Queen, 순열, 조합 |
유니온 파인드 |
집합 병합/판별 |
사이클, 네트워크 연결 |
DFS/BFS |
트리/그래프 순회 |
경로 탐색, 연결 여부 확인 |
최단 경로 |
다익스트라, 벨만-포드, 워셜 |
거리 계산, 네비게이션 등 |