본문 바로가기
카테고리 없음

코딩테스트에 주로 등장하는 알고리즘

by 멋대로 정보봇 2024. 6. 8.

코딩테스트에 주로 등장하는 알고리즘

코딩테스트는 개발자의 문제 해결 능력과 알고리즘 이해도를 평가하는 중요한 과정입니다. 이러한 테스트에서 주로 등장하는 알고리즘을 미리 학습하고 연습하면, 실전에서 더 나은 성과를 거둘 수 있습니다. 이번 포스팅에서는 코딩테스트에 자주 등장하는 알고리즘과 그 예제를 소개하겠습니다.

1. 정렬 알고리즘

정렬 알고리즘은 데이터를 특정 순서대로 정렬하는 방법을 말합니다. 코딩테스트에서 자주 등장하는 정렬 알고리즘은 다음과 같습니다:

  • 버블 정렬 (Bubble Sort):
    • 가장 간단한 정렬 알고리즘 중 하나로, 인접한 두 요소를 비교하여 정렬합니다.
    • 시간 복잡도: O(n^2)
  • 삽입 정렬 (Insertion Sort):
    • 배열의 요소를 순차적으로 비교하여 올바른 위치에 삽입합니다.
    • 시간 복잡도: O(n^2)
  • 퀵 정렬 (Quick Sort):
    • 분할 정복 알고리즘의 하나로, 피벗을 기준으로 배열을 나누어 정렬합니다.
    • 시간 복잡도: 평균 O(n log n)
  • 병합 정렬 (Merge Sort):
    • 분할 정복 알고리즘의 하나로, 배열을 반으로 나누어 정렬한 후 병합합니다.
    • 시간 복잡도: O(n log n)

예제 문제:

  • "정수 배열이 주어졌을 때, 이를 오름차순으로 정렬하시오."
def quick_sort(arr):
    if len(arr) <= 1:
        return arr
    pivot = arr[len(arr) // 2]
    left = [x for x in arr if x < pivot]
    middle = [x for x in arr if x == pivot]
    right = [x for x in arr if x > pivot]
    return quick_sort(left) + middle + quick_sort(right)

arr = [3, 6, 8, 10, 1, 2, 1]
print(quick_sort(arr))

2. 탐색 알고리즘

탐색 알고리즘은 데이터 구조 내에서 원하는 값을 찾는 방법을 말합니다. 주로 사용되는 탐색 알고리즘은 다음과 같습니다:

  • 이진 탐색 (Binary Search):
    • 정렬된 배열에서 절반씩 범위를 줄여가며 탐색합니다.
    • 시간 복잡도: O(log n)
  • 너비 우선 탐색 (Breadth-First Search, BFS):
    • 그래프 또는 트리에서 가까운 노드부터 탐색합니다.
    • 시간 복잡도: O(V + E) (V는 노드 수, E는 간선 수)
  • 깊이 우선 탐색 (Depth-First Search, DFS):
    • 그래프 또는 트리에서 깊이 우선으로 탐색합니다.
    • 시간 복잡도: O(V + E)

예제 문제:

  • "정렬된 배열에서 주어진 값을 찾는 프로그램을 작성하시오."
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

arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(binary_search(arr, 5))

3. 그래프 알고리즘

그래프 알고리즘은 노드와 간선으로 구성된 그래프 구조를 탐색하거나 최적의 경로를 찾는 방법을 말합니다. 주요 알고리즘은 다음과 같습니다:

  • 다익스트라 알고리즘 (Dijkstra's Algorithm):
    • 가중치가 있는 그래프에서 최단 경로를 찾는 알고리즘입니다.
    • 시간 복잡도: O(E + V log V)
  • 벨만-포드 알고리즘 (Bellman-Ford Algorithm):
    • 가중치가 음수일 수 있는 그래프에서 최단 경로를 찾는 알고리즘입니다.
    • 시간 복잡도: O(VE)
  • 플로이드-워셜 알고리즘 (Floyd-Warshall Algorithm):
    • 모든 노드 쌍 간의 최단 경로를 찾는 알고리즘입니다.
    • 시간 복잡도: O(V^3)

예제 문제:

  • "가중치가 있는 그래프에서 주어진 시작 노드에서 모든 노드로의 최단 경로를 찾으시오."
import heapq

def dijkstra(graph, start):
    distances = {node: float('infinity') for node in graph}
    distances[start] = 0
    pq = [(0, start)]
    while pq:
        current_distance, current_node = heapq.heappop(pq)
        if current_distance > distances[current_node]:
            continue
        for neighbor, weight in graph[current_node].items():
            distance = current_distance + weight
            if distance < distances[neighbor]:
                distances[neighbor] = distance
                heapq.heappush(pq, (distance, neighbor))
    return distances

graph = {
    'A': {'B': 1, 'C': 4},
    'B': {'A': 1, 'C': 2, 'D': 5},
    'C': {'A': 4, 'B': 2, 'D': 1},
    'D': {'B': 5, 'C': 1}
}
print(dijkstra(graph, 'A'))

4. 동적 계획법 (Dynamic Programming)

동적 계획법은 복잡한 문제를 작은 하위 문제로 나누어 해결하는 방법입니다. 주로 중복되는 계산을 줄여 효율성을 높입니다.

  • 피보나치 수열 (Fibonacci Sequence):
    • 동적 계획법을 사용하여 피보나치 수를 계산합니다.
  • 배낭 문제 (Knapsack Problem):
    • 제한된 용량의 배낭에 최대 가치를 담는 방법을 찾습니다.
  • 최장 공통 부분 수열 (Longest Common Subsequence):
    • 두 시퀀스의 최장 공통 부분 수열을 찾습니다.

예제 문제:

  • "피보나치 수열의 n번째 값을 동적 계획법으로 구하시오."
def fibonacci(n):
    fib = [0, 1]
    for i in range(2, n + 1):
        fib.append(fib[i - 1] + fib[i - 2])
    return fib[n]

print(fibonacci(10))

5. 문자열 알고리즘

문자열 알고리즘은 문자열을 처리하고 분석하는 방법을 말합니다. 코딩테스트에서 자주 등장하는 알고리즘은 다음과 같습니다:

  • KMP 알고리즘 (Knuth-Morris-Pratt):
    • 문자열에서 부분 문자열을 찾는 효율적인 알고리즘입니다.
    • 시간 복잡도: O(n + m)
  • 라빈-카프 알고리즘 (Rabin-Karp):
    • 해시 함수를 사용하여 문자열에서 부분 문자열을 찾습니다.
    • 시간 복잡도: 평균 O(n + m)
  • 트라이 자료구조 (Trie):
    • 문자열 집합을 저장하고 효율적으로 검색할 수 있는 자료구조입니다.

예제 문제:

  • "문자열에서 특정 패턴을 찾는 프로그램을 작성하시오."
def kmp(pattern, text):
    def compute_lps(pattern):
        lps = [0] * len(pattern)
        length = 0
        i = 1
        while i < len(pattern):
            if pattern[i] == pattern[length]:
                length += 1
                lps[i] = length
                i += 1
            else:
                if length != 0:
                    length = lps[length - 1]
                else:
                    lps[i] = 0
                    i += 1
        return lps

    lps = compute_lps(pattern)
    i = j = 0
    matches = []
    while i < len(text):
        if pattern[j] == text[i]:
            i += 1
            j += 1
        if j == len(pattern):
            matches.append(i - j)
            j = lps[j - 1]
        elif i < len(text) and pattern[j] != text[i]:
            if j != 0:
                j = lps[j - 1]
            else:
                i += 1
    return matches

text = "ABABDABACDABABCABAB"
pattern = "ABABCABAB"
print(kmp(pattern, text))

결론

코딩테스트에서 자주 등장하는 알고리즘을 미리 학습하고 연습하면, 실전에서 더 나은 성과를 거둘 수 있습니다.