파이썬 코딩테스트 강좌, 퀵 정렬

1. 서론

오늘은 파이썬을 활용하여 효과적으로 데이터를 정렬하는 알고리즘 중 하나인 퀵 정렬에 대해 다루어 보겠습니다. 퀵 정렬은 평균적으로 O(n log n)의 시간 복잡도를 가지며, 실제로도 매우 빠르고 효율적인 정렬 알고리즘입니다. 이 과정에서 우리는 퀵 정렬의 작동 원리에 대해 살펴보고, 파이썬으로 구현하는 방법을 알아보겠습니다.

2. 퀵 정렬이란?

퀵 정렬은 분할 정복 알고리즘의 일종으로, 배열을 두 개의 하위 배열로 나누고, 각각의 하위 배열을 재귀적으로 정렬하여 전체 배열을 정렬하는 방식입니다. 이 과정의 핵심은 ‘피벗’이라고 불리는 기준값을 선택하여, 해당 값을 기준으로 배열을 분할하는 것입니다.

2.1 퀵 정렬의 단계

  1. 배열에서 피벗 값을 선택합니다.
  2. 피벗을 기준으로 배열을 두 개의 하위 배열로 분할합니다. 첫 번째 하위 배열은 피벗보다 작은 값들로, 두 번째 하위 배열은 피벗보다 큰 값들로 구성됩니다.
  3. 위 과정을 재귀적으로 반복하여 하위 배열들을 정렬합니다.
  4. 결국 모든 하위 배열이 정렬되면, 전체 배열이 정렬된 상태가 됩니다.

2.2 피벗 선택

피벗을 선택하는 방법은 여러 가지가 있으며, 일반적으로 첫 번째 요소, 마지막 요소, 중간 요소 중 하나를 선택합니다. 더 나아가 랜덤하게 피벗을 선택하는 방법도 있으며, 이 방법은 최악의 경우에도 O(n log n)으로 유지하는 데 도움이 됩니다.

3. 문제 풀이

3.1 문제 설명

주어진 정수 배열을 입력으로 받아 정렬된 배열을 출력하는 함수를 작성하세요. 퀵 정렬 알고리즘을 사용해야 합니다.

3.2 문제 입력 및 출력 형식

  • 입력: 정수 배열 arr = [3, 6, 8, 10, 1, 2, 1]
  • 출력: 정렬된 배열 [1, 1, 2, 3, 6, 8, 10]

3.3 풀이 과정

이제 퀵 정렬 알고리즘을 파이썬으로 구현하는 과정을 단계별로 살펴보겠습니다.

3.3.1 피벗 선택 및 배열 분할

우선 피벗을 선택하고, 피벗을 기준으로 배열을 나누는 함수를 작성합니다. 다음은 이러한 작업을 수행하는 코드입니다.

    def partition(arr, low, high):
        pivot = arr[high]
        i = low - 1
        
        for j in range(low, high):
            if arr[j] <= pivot:
                i += 1
                arr[i], arr[j] = arr[j], arr[i]
        
        arr[i + 1], arr[high] = arr[high], arr[i + 1]
        return i + 1
    

3.3.2 퀵 정렬 함수 구현

이제 분할된 배열을 재귀적으로 정렬하는 함수를 구현합니다.

    def quick_sort(arr, low, high):
        if low < high:
            pi = partition(arr, low, high)
            quick_sort(arr, low, pi - 1)
            quick_sort(arr, pi + 1, high)
    

3.3.3 전체 코드

위에서 작성한 함수를 이용하여 전체 퀵 정렬 코드는 다음과 같습니다.

    def partition(arr, low, high):
        pivot = arr[high]
        i = low - 1
        
        for j in range(low, high):
            if arr[j] <= pivot:
                i += 1
                arr[i], arr[j] = arr[j], arr[i]
        
        arr[i + 1], arr[high] = arr[high], arr[i + 1]
        return i + 1

    def quick_sort(arr, low, high):
        if low < high:
            pi = partition(arr, low, high)
            quick_sort(arr, low, pi - 1)
            quick_sort(arr, pi + 1, high)

    arr = [3, 6, 8, 10, 1, 2, 1]
    quick_sort(arr, 0, len(arr) - 1)
    print("정렬된 배열:", arr)
    

4. 퀵 정렬의 장점과 단점

4.1 장점

  • 평균적으로 O(n log n)의 시간 복잡도를 가지므로 빠르다.
  • 재귀적 성질로 인해 코드가 간결하다.
  • 제자리 정렬(in-place sorting)을 지원하여 추가적인 메모리 사용이 적다.

4.2 단점

  • 최악의 경우 (이미 정렬된 배열 등) O(n^2)의 시간 복잡도를 가질 수 있다.
  • 재귀 호출이 많아 스택 오버플로우가 발생할 수 있다.

5. 결론

이번 강좌에서는 파이썬을 이용한 퀵 정렬 알고리즘의 구현 과정을 살펴보았습니다. 퀵 정렬은 많은 상황에서 효과적인 정렬 방법이지만, 사용 시 주의할 점도 존재합니다. 알고리즘의 성질을 이해하고, 적절한 상황에서 올바르게 적용하는 것이 중요합니다.

퀵 정렬을 이해하는 데 많은 도움이 되었기를 바랍니다. 다음 강좌에서는 다른 정렬 알고리즘에 대해 자세히 알아보도록 하겠습니다. 감사합니다!

파이썬 코딩테스트 강좌, 케빈 베이컨의 6단계 법칙

안녕하세요! 오늘은 코딩 테스트에서 자주 출제되는 알고리즘 문제 중 하나인 “케빈 베이컨의 6단계 법칙”에 대해 알아보겠습니다. 이 문제는 다양한 그래프 이론의 개념을 활용하여 해결할 수 있으며, 특히 너비 우선 탐색(BFS)이나 깊이 우선 탐색(DFS)과 같은 기본적인 탐색 알고리즘을 연습할 수 있는 좋은 기회를 제공합니다.

1. 문제 설명

케빈 베이컨의 6단계 법칙은 유명한 사회 관계망 이론 중 하나로, 두 사람 사이의 관계를 통한 연결고리가 6단계 이내에 존재한다는 이론입니다. 이를 코드로 구현해보는 문제입니다.

문제는 다음과 같습니다:

주어진 N명의 사용자와 그들 간의 관계가 주어질 때,
각 사용자 간의 케빈 베이컨의 점수를 계산하고,
가장 점수가 낮은 사용자를 출력하는 프로그램을 작성하시오.
점수는 해당 사용자와의 최단 거리의 합입니다.

2. 입력 형식

첫 줄에는 사용자 수 N(1 ≤ N ≤ 100)과 관계의 수 M(0 ≤ M ≤ 4,900)이 주어집니다.

다음 M개의 줄에는 두 정수 a, b가 주어지며, 이는 사용자 a와 b가 서로 친구라는 것을 나타냅니다.

3. 출력 형식

케빈 베이컨 점수가 가장 낮은 사용자의 번호를 출력합니다. 점수가 같은 경우에는 가장 번호가 작은 사용자를 출력합니다.

4. 문제 해결 과정

이 문제를 풀기 위해선 다음 단계를 따라야 합니다:

4.1. 그래프 생성

먼저 각 사용자와 친구 관계를 나타내는 그래프를 인접 리스트 형태로 생성합니다. 이 그래프는 딕셔너리나 리스트를 사용하여 표현할 수 있습니다.

graph = {i: [] for i in range(1, N + 1)}
for _ in range(M):
    a, b = map(int, input().split())
    graph[a].append(b)
    graph[b].append(a)

4.2. BFS 또는 DFS 구현

각 사용자에 대해 BFS 또는 DFS를 통해 다른 사용자와의 최단 거리를 계산합니다. BFS가 최단 경로를 보장하기 때문에 이 문제에는 BFS를 사용하는 것이 더 적합합니다.

def bfs(start, graph):
    queue = [start]
    visited = {start: 0}
    
    while queue:
        current = queue.pop(0)
        
        for neighbor in graph[current]:
            if neighbor not in visited:
                visited[neighbor] = visited[current] + 1
                queue.append(neighbor)
    return sum(visited.values())

4.3. 점수 계산

모든 사용자의 케빈 베이컨 점수를 계산합니다. BFS 결과를 이용하여 점수를 저장하고, 가장 낮은 점수를 찾습니다.

min_score = float('inf')
user_with_min_score = -1
for user in range(1, N + 1):
    score = bfs(user, graph)
    if score < min_score:
        min_score = score
        user_with_min_score = user
    elif score == min_score:
        user_with_min_score = min(user_with_min_score, user)

5. 전체 코드

이제, 위 과정을 통합한 전체 코드를 작성해보겠습니다.

from collections import deque

def bfs(start, graph):
    queue = deque([start])
    visited = {start: 0}
    
    while queue:
        current = queue.popleft()
        
        for neighbor in graph[current]:
            if neighbor not in visited:
                visited[neighbor] = visited[current] + 1
                queue.append(neighbor)
    return sum(visited.values())

def find_kevin_bacon(graph, n):
    min_score = float('inf')
    user_with_min_score = -1
    
    for user in range(1, n + 1):
        score = bfs(user, graph)
        if score < min_score:
            min_score = score
            user_with_min_score = user
        elif score == min_score:
            user_with_min_score = min(user_with_min_score, user)
    
    return user_with_min_score

# 입력
N, M = map(int, input().split())
graph = {i: [] for i in range(1, N + 1)}
for _ in range(M):
    a, b = map(int, input().split())
    graph[a].append(b)
    graph[b].append(a)

# 결과 출력
result = find_kevin_bacon(graph, N)
print(result)

6. 코드 설명

코드는 주어진 N과 M 값을 입력받고, 친구 관계를 바탕으로 그래프를 구성한 다음, 각 사용자에 대한 BFS를 통해 케빈 베이컨 점수를 계산합니다. 마지막으로 가장 점수가 낮은 사용자의 번호를 출력합니다. 이 문제를 통해 그래프 이론과 BFS 알고리즘에 대한 좋은 연습이 될 것입니다.

7. 성능 분석

이 알고리즘의 시간 복잡도는 O(V + E)로, V는 정점(사용자)의 수, E는 간선(관계)의 수입니다. 이 경우 N이 100이라고 가정할 때, 최악의 경우 4900개의 관계를 가질 수 있으므로, 총 100번의 BFS 호출 시 약 495,000번의 탐색이 일어납니다. 이는 주어진 시간 내에 충분히 처리 가능한 범위에 속합니다.

8. 결론

케빈 베이컨의 6단계 법칙을 활용한 이 문제는 그래프 이론의 기초를 다지고, BFS의 활용법을 익힐 수 있는 좋은 기회입니다. 다양한 변형 문제를 통해 추가적으로 연습한다면 알고리즘적 사고를 더욱 재고할 수 있을 것입니다. 앞으로도 다양한 문제를 통해 코딩 테스트 준비를 지속적으로 해나가시길 바랍니다!

감사합니다!

파이썬 코딩테스트 강좌, 칵테일 만들기

문제 설명

당신은 한 수페르마켓의 바에서 일하는 바텐더입니다. 바텐더로서 다양한 칵테일을 만들고 싶습니다. 당신은 각각의 칵테일을 만들기 위해 필요한 재료들의 목록을 보유하고 있으며, 특정 재료가 얼마나 필요한지 알고 있습니다.

당신은 사용자에게 원하는 칵테일의 이름과 가용한 재료 목록을 제공받습니다. 사용자는 재료의 세트에서 원하는 칵테일을 만들 수 있는지 알고 싶어합니다. 제시된 재료로 원하는 칵테일을 만들 수 있다면 ‘가능’이라고 출력하고, 그렇지 않다면 ‘불가능’이라고 출력하세요.

입력 형식

  • 첫 번째 줄은 칵테일 이름입니다. (예: “마가리타”)
  • 두 번째 줄은 사용 가능한 재료들로 이루어진 문자열입니다. (예: “테킬라,라임주스,트리플섹”)
  • 세 번째 줄은 각 재료와 칵테일에 필요한 재료의 수량으로 이루어진 문자열입니다. (예: “테킬라:50,라임주스:30,트리플섹:10”)

출력 형식

칼렉틀을 만들 수 있다면 “가능”이라고, 그렇지 않다면 “불가능”이라고 출력하세요.

제약 조건

  • 재료명의 길이는 1에서 50자 이내입니다.
  • 수량은 모두 양의 정수입니다.
  • 재료는 쉼표로 구분됩니다.

문제 풀이

이 문제를 푸는 방법에 대해 단계적으로 알아보겠습니다.

1단계: 입력 파싱

먼저, 사용자로부터 전달받은 입력 데이터를 파싱하여 각각의 요소를 추출합니다. 칵테일 이름, 사용 가능한 재료 목록, 칵테일의 재료 목록을 파악해야 합니다.

2단계: 데이터 구조

재료명과 이를 만들기 위해 필요한 수량을 저장하기 위해 딕셔너리 자료구조를 사용할 것입니다. 각 재료를 키로 하고, 필요한 수량을 값으로 하는 형태로 저장되며, 사용 가능한 재료는 셋(Set)으로 저장합니다.

3단계: 비교 및 확인

이제 재료 목록이 준비되었으므로, 사용자가 원하는 칵테일을 만들기 위해 필요한 모든 재료가 사용 가능한 재료에 포함되어 있는지를 확인해야 합니다.

4단계: 결과 출력

모든 조건을 만족하는 경우 “가능”을 출력하고, 그렇지 않으면 “불가능”이라고 출력합니다.

예제 코드

        
def cocktail_availability(cocktail_name, available_ingredients, required_ingredients):
    # 재료를 저장하는 딕셔너리 생성
    required_dict = {}
    for item in required_ingredients.split(','):
        ingredient, quantity = item.split(':')
        required_dict[ingredient] = int(quantity)
    
    # 사용 가능한 재료를 저장하는 세트 생성
    available_set = set(available_ingredients.split(','))
    
    # 필요한 재료가 모두 사용 가능한지 확인
    for ingredient, quantity in required_dict.items():
        if ingredient not in available_set:
            return '불가능'
    
    return '가능'

# 예시 입력
cocktail_name = "마가리타"
available_ingredients = "테킬라,라임주스,트리플섹"
required_ingredients = "테킬라:50,라임주스:30,트리플섹:10"

# 함수 호출
result = cocktail_availability(cocktail_name, available_ingredients, required_ingredients)
print(result)  # 출력: 가능
        
    

결과

입력 데이터에 기반하여 칵테일을 만들 수 있는지 확인했습니다. 예를 들어, 위에 제시된 입력으로 함수를 실행하면 “가능”이라는 결과를 반환합니다. 즉, 사용자는 원하는 칵테일을 만들 수 있습니다.

해결책의 복잡도 분석

시간 복잡도는 O(n)입니다. 여기서 n은 재료의 수입니다. 각각의 재료에 대해 딕셔너리와 셋을 업데이트하고 비교하므로 선형 시간 복잡도를 가집니다.

공간 복잡도 또한 O(n)입니다. 필요한 재료를 저장하기 위한 딕셔너리와 사용 가능한 재료를 위한 세트가 필요하기 때문입니다.

파이썬 코딩테스트 강좌, 카드 게임

우리는 종종 코딩 테스트에서 특정한 규칙을 가진 게임 문제를 접하게 됩니다. 이 강좌에서는 카드 게임과 관련된 문제를 하나 다루어보겠습니다. 카드 게임 문제는 알고리즘 및 자료구조를 활용하여 효과적으로 해결할 수 있는 좋은 예시입니다.

문제 설명

두 명의 플레이어가 카드 게임을 하고 있습니다. 각 플레이어는 1부터 N까지의 숫자가 적힌 고유한 카드를 가지고 있습니다. 플레이어는 서로 번갈아 가며 카드를 한 장씩 선택합니다. 각 플레이어는 고른 카드의 숫자만큼 점수를 획득합니다.

문제: 두 플레이어가 받을 수 있는 점수를 최대로 하여 게임을 진행하고, 최종 점수를 구하는 함수를 작성하세요. 아래와 같은 조건이 있습니다:

  • 각 플레이어는 1부터 N까지의 카드에서 카드를 선택할 수 있습니다.
  • 각 플레이어는 한 번에 하나의 카드를 선택할 수 있으며, 동일한 카드를 다시 선택할 수 없습니다.
  • 최종 점수는 각 플레이어가 선택한 카드의 합입니다.

입력

  • 정수 N (1 ≤ N ≤ 100) – 카드의 개수

출력

  • 두 플레이어의 점수 합계

알고리즘 접근법

이 문제는 간단한 점수 계산과 카드 선택에 의한 최적화를 요구합니다. 우리는 다음의 접근 방법으로 문제를 풀어볼 것입니다:

  1. 카드의 숫자를 리스트로 만들어서 플레이어가 선택할 수 있도록 합니다.
  2. 각각의 플레이어가 카드의 점수를 계산할 수 있는 방법을 정의합니다.
  3. 두 플레이어의 카드 선택을 시뮬레이션하여 최종 점수를 계산합니다.

코드 구현

이제 본격적으로 문제를 해결하기 위한 코드를 구현해 보겠습니다. 아래는 문제 해결을 위한 파이썬 코드입니다:

def card_game(n):
    # 카드 숫자를 생성합니다.
    cards = list(range(1, n + 1))
    
    # 플레이어의 점수 초기화
    player1_score = 0
    player2_score = 0
    
    # 플레이어들은 번갈아 가며 카드를 선택
    turn = 0
    while cards:
        # 현재 플레이어의 선택
        if turn % 2 == 0:  # Player 1의 차례
            chosen_card = max(cards)  # 가장 높은 값을 선택
            player1_score += chosen_card
        else:  # Player 2의 차례
            chosen_card = min(cards)  # 가장 낮은 값을 선택
            player2_score += chosen_card

        # 선택한 카드 제거
        cards.remove(chosen_card)
        turn += 1

    return player1_score + player2_score

# 예시
n = 5
print("최종 점수:", card_game(n))

코드 설명

이제 작성한 코드에 대해 간략하게 설명드리겠습니다:

  1. def card_game(n): – 카드 게임 함수를 정의합니다. 입력으로 카운트 N을 받습니다.
  2. cards = list(range(1, n + 1)) – 1부터 N까지의 카드를 리스트로 생성합니다.
  3. player1_scoreplayer2_score – 두 플레이어의 점수를 각각 초기화합니다.
  4. while cards: – 카드가 남아 있는 동안 계속해서 반복합니다.
  5. if turn % 2 == 0: – 플레이어의 턴을 확인하고 번갈아 가며 카드를 선택합니다.
  6. 플레이어의 선택에 따라 최대 카드 또는 최소 카드를 선택하고 점수에 추가합니다.
  7. cards.remove(chosen_card) – 선택한 카드를 카드 리스트에서 제거합니다.
  8. 최종적으로 두 플레이어의 점수 합계를 반환합니다.

테스트 케이스

최종 점수를 계산하는 함수를 테스트해보겠습니다. 여러 가지 테스트 케이스를 만들어 다양한 결과를 확인해보겠습니다:

print("N=3:", card_game(3))  # 출력: 6
print("N=4:", card_game(4))  # 출력: 10
print("N=5:", card_game(5))  # 출력: 15
print("N=10:", card_game(10))  # 출력: 55

결론

이번 강좌에서는 간단한 카드 게임 문제를 통해 알고리즘 및 자료구조의 기본적인 사용법을 배워보았습니다. 카드의 선택 마다 전략적으로 점수를 얻는 방법을 고민해야 함을 알 수 있었습니다.

이와 같이 카드 게임 문제는 알고리즘적 사고를 기르는 데 도움을 주며, 다양한 변형 문제를 통해 연습할 수 있습니다. 이 강좌에서 다룬 문제를 응용하여 더 복잡한 카드 게임이나 다른 형태의 문제로 발전시켜 볼 수 있습니다. 앞으로도 다양한 알고리즘 문제 풀이를 통해 실력을 향상시키시길 바랍니다!

파이썬 코딩테스트 강좌, 카드 정렬하기

알고리즘 문제 해결 능력은 기술 면접에서 중요한 요소입니다. 이번 포스트에서는 ‘카드 정렬하기’라는 알고리즘 문제를 다루고, 문제 해결 과정을 단계별로 살펴보겠습니다. 이 문제는 실제 코딩 테스트에서 자주 등장하는 유형 중 하나로, 주어진 카드들을 특정한 방식으로 정렬하는 작업을 포함합니다. 이 글을 통해 문제에 대한 이해도를 높이고, 실전에서 응용할 수 있는 방법을 배워봅시다.

문제 정의

주어진 N개의 카드가 있습니다. 이 카드들은 각각의 숫자로 표시되어 있으며, 이 숫자들은 정수입니다. 우리의 목표는 이 카드들을 정렬하는 것입니다. 하지만 이 과정에서 특정한 규칙을 따라야 합니다.

함수 시그니처:
def card_sorting(cards: List[int]) -> List[int]:
    pass

여기서 cards는 정수들로 이루어진 리스트이며, 정렬된 카드를 반환해야 합니다. 하지만 각 카드는 정해진 방법으로 정렬해야 합니다. 주의할 점은 카드 정렬을 수행하는 데 관련된 특정한 조건이 있을 수 있으며, 이러한 조건들을 효과적으로 처리해야 합니다.

문제 접근

이제 문제를 해결하기 위한 접근 방식을 살펴보겠습니다. 카드 정렬하기 문제는 다음과 같은 세부적인 규칙이 있다고 가정하겠습니다:

  • 카드는 주어진 순서대로 나열되어 있으며, 각 카드에 대해 인접한 카드와 비교하여 정렬합니다.
  • 정렬 과정에서 더 작은 숫자의 카드를 왼쪽으로 이동시킵니다.
  • 각 카드의 숫자는 고유하며 중복되지 않습니다.

이제, 카드들을 정렬하기 위해 다양한 알고리즘을 사용할 수 있습니다. 일반적으로 사용되는 알고리즘은 다음과 같습니다:

  • 버블 정렬(Bubble Sort)
  • 선택 정렬(Selection Sort)
  • 삽입 정렬(Insertion Sort)
  • 퀵 정렬(Quick Sort)
  • 병합 정렬(Merge Sort)

각각의 알고리즘에 대해서는 이론적인 설명도 필요하므로, 이들 각각에 대해 간단한 설명을 추가하겠습니다.

버블 정렬(Bubble Sort)

버블 정렬은 가장 간단한 정렬 알고리즘 중 하나입니다. 이 알고리즘은 인접한 두 요소를 비교하여 정렬하는 방식입니다. 리스트의 크기만큼 반복하며, 인접한 요소들을 비교한 후, 필요에 따라 서로 교환합니다. 최악의 경우 O(N²)의 시간 복잡도를 가집니다.

선택 정렬(Selection Sort)

선택 정렬은 주어진 리스트에서 가장 작은 값을 찾아서 정렬을 계속하는 방식입니다. 리스트의 크기만큼 반복하면서 매번 남은 요소 중에서 가장 작은 값을 찾아서 현재 위치에 정렬합니다. 이 또한 O(N²)의 시간 복잡도를 가집니다.

삽입 정렬(Insertion Sort)

삽입 정렬은 이미 정렬된 데이터에 새로운 요소를 삽입하는 방식입니다. 초기에는 첫 번째 요소가 정렬된 상태로 간주하고, 그 다음 요소부터 정렬된 위치에 삽입합니다. 일반적으로 O(N²)의 시간 복잡도를 가지나, 데이터가 거의 정렬되어 있을 경우 더 좋은 성능을 보입니다.

퀵 정렬(Quick Sort)

퀵 정렬은 분할 정복 알고리즘을 기반으로 하며, 하나의 피벗 요소를 선택하여 리스트를 피벗보다 작은 값과 큰 값을 기준으로 분할합니다. 그 후, 각 부분 리스트에 대해 재귀적으로 퀵 정렬을 수행합니다. 평균적으로 O(N log N)의 시간 복잡도를 가집니다.

병합 정렬(Merge Sort)

병합 정렬 또한 분할 정복 기법을 사용합니다. 리스트를 반으로 나누고, 각각의 리스트를 재귀적으로 정렬한 다음 두 리스트를 병합하여 정렬합니다. 역시 O(N log N)의 시간 복잡도를 가집니다.

문제 해결 – 카드 정렬하기 구현

이제 카드 정렬하기 문제를 해결하기 위한 파이썬 코드를 구현해 보겠습니다. 우리는 이 문제를 퀵 정렬를 사용하여 해결하도록 하겠습니다.

from typing import List

def quick_sort(cards: List[int]) -> List[int]:
    if len(cards) <= 1:
        return cards
    pivot = cards[len(cards) // 2]
    left = [x for x in cards if x < pivot]
    middle = [x for x in cards if x == pivot]
    right = [x for x in cards if x > pivot]
    return quick_sort(left) + middle + quick_sort(right)

def card_sorting(cards: List[int]) -> List[int]:
    return quick_sort(cards)

테스트 케이스

코드가 구현되었으니, 다양한 테스트 케이스를 통해 올바르게 작동하는지 확인해보겠습니다.

if __name__ == "__main__":
    test_cases = [
        [3, 6, 8, 10, 1, 2, 1],
        [5, 2, 9, 1, 5, 6],
        [2, 7, 1, 8, 2, 3, 5]
    ]
    
    for cards in test_cases:
        sorted_cards = card_sorting(cards)
        print(f"Original: {cards} -> Sorted: {sorted_cards}")

이 코드를 실행하면 다음과 같은 결과를 얻을 수 있습니다:

Original: [3, 6, 8, 10, 1, 2, 1] -> Sorted: [1, 1, 2, 3, 6, 8, 10]
Original: [5, 2, 9, 1, 5, 6] -> Sorted: [1, 2, 5, 5, 6, 9]
Original: [2, 7, 1, 8, 2, 3, 5] -> Sorted: [1, 2, 2, 3, 5, 7, 8]

결론

이번 글에서는 ‘카드 정렬하기’ 문제를 해결하기 위해 다양한 정렬 알고리즘을 살펴보고, 그 중 퀵 정렬 알고리즘을 사용하여 문제를 해결했습니다. 파이썬을 이용한 구현 방법과 함께 적절한 테스트 케이스를 통해 코드의 정확성을 검증하였습니다. 이와 같은 문제를 통해 알고리즘적인 사고를 키우고, 코딩 테스트에서 좋은 성과를 거두기를 바랍니다. 계속해서 다양한 문제를 연습하고, 여러분의 실력을 키워나가세요!