파이썬 코딩테스트 강좌, 게임 개발하기

오늘은 파이썬을 활용하여 게임 개발을 위한 알고리즘 문제를 하나 해결해보겠습니다. 이 강좌에서는 알고리즘 문제를 통해 문제 해결 능력을 기르고, 실제 게임 개발에 적용할 수 있는 다양한 기술과 개념을 익히겠습니다.

문제 설명

문제: “이상한 격자” 게임

격자 형태의 게임 보드가 주어지고, 각 칸에는 정수가 저장되어 있습니다. 게임에서 플레이어는 보드의 경계 바깥에서 시작하여, 최대 3칸까지 이동할 수 있습니다. 단, 플레이어가 이동할 수 있는 점수는 각 칸의 값의 합으로 계산됩니다. 플레이어는 최종적으로 0 이상의 점수를 가지도록 경과하는 이동을 선택해야 합니다. 게임 보드의 모든 칸을 방문하면서 가능한 최대 점수를 구하세요.

입력

        첫 번째 줄: 격자의 크기 N (1 ≤ N ≤ 10)
        그 다음 N줄: 격자의 각 원소 (−100 ≤ 요소 ≤ 100)
    

출력

        가능한 최대 점수
    

예제 입력

    3
    10 -1 2
    -5 20 3
    2 -3 -4
    

예제 출력

    32
    

문제 분석

이 문제는 ‘DFS(Depth First Search)’ 기법을 사용하여 모든 가능한 경로를 탐색하고, 그 중 최대 점수를 찾아야 합니다. 먼저, 격자의 각 칸에 대한 이동 경로를 정의해야 합니다. 주어진 규칙에 따라, 시작점에서 가능한 모든 경로를 탐색하여 가장 높은 총 점수를 찾아 보겠습니다.

문제 해결 과정

1. 기본 구조 설정

문제를 해결하기 위해 재귀 함수를 통해 DFS를 구현합니다. 재귀 함수는 현재 위치에서 갈 수 있는 모든 경로를 탐색하는 역할을 합니다. 다음은 기본 틀입니다.

def dfs(x, y, score):
    # 현재 위치에서 가능한 모든 경로를 탐색하고 최대 점수를 반환하는 함수
    pass
    

2. 경로 탐색 로직 구현

이제 각 칸에서 상하좌우로 이동할 때의 위치를 계산할 수 있어야 합니다. 이를 위해서 방향 배열을 사용하겠습니다. 다음의 방향 배열을 사용하여 경로를 탐색할 수 있습니다.

dx = [0, 1, 0, -1] # 좌우
dy = [1, 0, -1, 0] # 상하

3. 재귀 함수 구현

이제 DFS 함수 안에서 재귀적으로 이동하며 점수를 계산하도록 하겠습니다. 격자의 크기와 현재 점수를 기반으로 이동 가능성을 체크하고, 경계 조건을 설정합니다.

def dfs(x, y, score, visited):
    if x < 0 or x >= N or y < 0 or y >= N or visited[x][y]:
        return score
    
    visited[x][y] = True
    score += grid[x][y] # 현재 점수에 현재 위치의 점수를 더합니다.
    
    max_score = score
    for i in range(4):
        new_x = x + dx[i]
        new_y = y + dy[i]
        max_score = max(max_score, dfs(new_x, new_y, score, visited))
    
    visited[x][y] = False # 백트래킹
    return max_score

4. 메인 함수 구현

모든 경로를 시작하기 위해 메인 함수를 정의해야 합니다. 이 함수에서 격자를 입력받고, DFS 탐색을 시작합니다. 최종적으로 최대 점수를 출력합니다.

def main():
    global grid, N
    N = int(input())
    grid = [list(map(int, input().split())) for _ in range(N)]
    
    visited = [[False]*N for _ in range(N)]
    max_total_score = 0
    
    # 모든 위치에서 DFS를 시작합니다.
    for i in range(N):
        for j in range(N):
            max_total_score = max(max_total_score, dfs(i, j, 0, visited))
    
    print(max_total_score)

5. 전체 코드

모든 부분을 통합한 전체 코드는 다음과 같습니다.

def dfs(x, y, score, visited):
    if x < 0 or x >= N or y < 0 or y >= N or visited[x][y]:
        return score
    
    visited[x][y] = True
    score += grid[x][y]
    
    max_score = score
    for i in range(4):
        new_x = x + dx[i]
        new_y = y + dy[i]
        max_score = max(max_score, dfs(new_x, new_y, score, visited))
    
    visited[x][y] = False
    return max_score

def main():
    global grid, N
    N = int(input())
    grid = [list(map(int, input().split())) for _ in range(N)]
    
    visited = [[False]*N for _ in range(N)]
    max_total_score = 0
    
    for i in range(N):
        for j in range(N):
            max_total_score = max(max_total_score, dfs(i, j, 0, visited))
    
    print(max_total_score)

if __name__ == "__main__":
    main()

결론

이 문제를 통해 게임의 기준 환경에서 어떤 방법으로 DFS를 활용하여 경로를 탐색하고 점수를 최대화할 수 있는지를 배웠습니다. 알고리즘을 통한 문제 해결 능력을 기르고, 파이썬으로 코딩 문제를 해결함으로써 더욱 효과적으로 게임 개발자로서의 능력을 향상시킬 수 있습니다.

추가학습 자료

다음과 같은 자료를 참고하면 더욱 깊이 있는 학습이 가능합니다:

파이썬 코딩테스트 강좌, 거짓말쟁이가 되긴 싫어

문제 설명

우리 동네에는 N명의 사람들이 있습니다. 각 사람은 각각의 닉네임을 가지고 있으며, 일부는 서로에게 거짓말을 합니다. 거짓말은 단순히 상대방에게 ‘자신의 닉네임’을 남기고 약속을 어기는 행위입니다. 여러분은 이러한 상황에서 실제로 거짓말을 한 사람의 닉네임을 찾고자 합니다.

N명의 사람에 대해 다음과 같은 정보를 제공합니다:

  • 자신의 닉네임
  • 서로가 서로에게 한 거짓말의 수

입력 형식

첫째 줄에 N (1 ≤ N ≤ 100,000) 이 주어집니다. 둘째 줄부터 N개의 줄에 각 사람의 닉네임과 그 사람이 한 거짓말의 수가 주어집니다.

출력 형식

거짓말을 한 사람의 닉네임을 한 줄에 하나씩 출력합니다. 만약 거짓말을 한 사람이 없다면 “거짓말쟁이가 없습니다.”라는 메시지를 출력합니다.

예제

    입력:
    3
    영희 1
    철수 0
    민수 2

    출력:
    영희
    민수
    

문제 풀이

이 문제를 풀기 위해서는 주어진 입력을 바탕으로 각 개인의 닉네임과 그들이 한 거짓말의 수를 파악해야 합니다. 주어진 데이터 구조를 사용하여 문제를 해결하는 과정은 다음과 같습니다:

1단계: 데이터 구조 설계

각 사람의 정보를 처리하기 위해, 우리는 리스트를 사용하여 사람들의 닉네임과 그들이 한 거짓말의 수를 저장할 것입니다. 이 때, 각 사람의 정보를 저장할 수 있는 튜플이나 딕셔너리를 사용해야 합니다.

2단계: 입력 데이터 수집

사용자로부터 입력을 받을 때, 먼저 사람 수 N을 입력받고 다음 N개의 라인에서는 각 사람의 정보를 읽어옵니다. 이때, 각 정보를 분리하여 저장합니다.

3단계: 거짓말쟁이 추출

거짓말을 한 사람들을 추출하기 위해, 거짓말의 수가 0보다 큰 모든 사람의 닉네임을 저장해야 합니다. 이를 위해 조건문을 사용하여 각 인물의 거짓말 수를 체크합니다.

4단계: 결과 출력

최종적으로 추출한 닉네임 리스트를 출력합니다. 만약 리스트가 비어있다면, “거짓말쟁이가 없습니다.”라는 메시지를 출력합니다.

코드 구현

그럼 이제 위의 논리를 바탕으로 코드를 구현해보겠습니다:

def find_liars(n, people):
    liars = []
    
    for name, lies in people:
        if lies > 0:
            liars.append(name)
    
    if liars:
        return liars
    else:
        return ["거짓말쟁이가 없습니다."]

if __name__ == "__main__":
    n = int(input("사람 수를 입력하세요: "))
    people = []

    for _ in range(n):
        entry = input("이름과 거짓말 수를 입력하세요: ").split()
        name = entry[0]
        lies = int(entry[1])
        people.append((name, lies))

    result = find_liars(n, people)
    for liar in result:
        print(liar)

코드 설명

위의 코드는 전체 프로세스를 간단하게 반환합니다. 각 단계에서 사람들이 입력한 정보를 저장하고, 이를 기반으로 거짓말을 한 이들의 닉네임을 판별합니다.

함수 설명

  • find_liars(n, people): 주어진 사람 수와 사람들의 정보를 받아 거짓말을 한 사람들의 닉네임 리스트를 반환합니다.
  • if __name__ == "__main__":: 메인 프로그램 실행 부분으로, 사용자로부터 입력받은 내용을 처리합니다.

결론

이번 문제를 통해, 간단한 데이터 구조와 리스트 이해를 바탕으로 코딩 테스트에서 자주 등장하는 유형의 문제를 해결하였습니다. 이번 문제 풀이 과정을 통해 코딩 테스트를 준비하는데 큰 도움이 되길 바랍니다.

파이썬 코딩테스트 강좌, 가장 큰 정사각형 찾기

코딩 테스트에서 자주 등장하는 문제 중 하나는 이차원 배열에서 가장 큰 정사각형을 찾는 문제입니다. 이 문제는 다음과 같은 방식으로 정의할 수 있습니다.

문제 정의

주어진 이진 행렬 (0과 1로 구성된 2차원 배열)에서 1로 구성된 가장 큰 정사각형의 넓이를 구하시오.

예를 들어, 다음과 같은 행렬이 있다고 가정합시다.

    [
        [1, 0, 1, 0, 0],
        [1, 0, 1, 1, 1],
        [1, 1, 1, 1, 1],
        [1, 0, 0, 1, 0]
    ]
    

위의 행렬에서 가장 큰 정사각형은 (1, 1)부터 (3, 3)까지의 영역으로, 크기는 9입니다.

문제 접근과 풀이 과정

이 문제를 해결하기 위해서는 동적 프로그래밍(Dynamic Programming) 방법을 사용할 수 있습니다. 이 방법론은 문제를 더 작은 하위 문제로 나누어 해결하고, 그 결과를 사용하여 최종 결과를 도출합니다.

동적 프로그래밍을 사용한 접근

1. 우리는 먼저 주어진 행렬의 크기를 가져오고, 동적 프로그래밍을 위한 2차원 배열 dp를 정의합니다. 이 dp 배열의 각 요소는 특정 위치에서의 가장 큰 정사각형의 한 변의 길이를 나타냅니다.

2. 초기화: dp 배열의 각 요소를 0으로 초기화합니다. 다만, 주어진 행렬의 첫 번째 행과 첫 번째 열은 주어진 행렬이 1인 위치에 대해서만 1로 설정합니다.

3. dp 배열을 채워나가는 방식: 이진 행렬의 각각의 요소를 살펴보면서, 특정 위치 (i, j)의 값이 1인 경우, dp[i][j] 값은 dp[i-1][j], dp[i][j-1], dp[i-1][j-1] 중 최소값 + 1로 설정합니다. 이는 가장 큰 정사각형의 변을 계산하는 방법입니다.

4. 결과: dp 배열에서 가장 큰 값을 찾아야 하며 이 값의 제곱이 우리가 구하고자 하는 정사각형의 넓이가 됩니다.

동적 프로그래밍 구현

이제 위의 방법을 토대로 파이썬 코드를 작성해 보겠습니다.

    
def maximalSquare(matrix):
    if not matrix:
        return 0

    max_square_len = 0
    rows = len(matrix)
    cols = len(matrix[0])
    dp = [[0] * cols for _ in range(rows)]

    for i in range(rows):
        for j in range(cols):
            if matrix[i][j] == '1':
                if i == 0 or j == 0:
                    dp[i][j] = 1
                else:
                    dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1

                max_square_len = max(max_square_len, dp[i][j])

    return max_square_len * max_square_len
    
    

코드 설명

코드의 첫 번째 줄에서는 주어진 행렬이 비어있지 않은지를 체크합니다. 비어있다면 결과는 0이 됩니다.

그 다음, 행렬의 행과 열의 크기를 가져오고, dp 배열을 생성합니다. 이 배열은 주어진 이진 행렬과 동일한 크기를 가지며 각 요소는 0으로 초기화됩니다.

포문을 통해 각 요소를 반복하며, 현재 요소가 1인 경우에만 처리를 진행합니다. 이 때, 각 요소를 처리하기 위해서는 위에서 언급한 관계를 사용하여 dp 배열을 채워 나갑니다. 여기서 가장 큰 정사각형의 변의 길이를 항상 추적하여 업데이트합니다.

마지막에는 가장 큰 정사각형의 넓이를 반환합니다.

복잡도 분석

위의 알고리즘은 O(n * m)의 시간 복잡도를 가집니다. 여기서 n은 행렬의 행의 수, m은 열의 수입니다. 공간 복잡도는 O(n * m)으로, 이는 dp 배열을 저장하기 위한 공간입니다.

예시와 함께 하기

이제 이 함수를 사용하여 주어진 행렬에서 가장 큰 정사각형을 찾아보겠습니다.

    
matrix = [
    ["1", "0", "1", "0", "0"],
    ["1", "0", "1", "1", "1"],
    ["1", "1", "1", "1", "1"],
    ["1", "0", "0", "1", "0"]
]
print(maximalSquare(matrix))  # 9
    
    

결론

이 문제는 코딩 테스트에서 자주 등장하는 문제 유형 중 하나입니다. 연습을 통해 이 문제를 잘 이해하고 해결할 수 있다면, 유사한 다른 문제들을 푸는 데에도 큰 도움이 될 것입니다. 더 나아가, 동적 프로그래밍의 원리를 이해하고 적용할 수 있는 능력은 여러 알고리즘 문제 해결에 유용하게 작용할 것입니다.

추가적으로, 이진 행렬을 더 복잡한 형태로 확장하는 복잡한 변형 문제를 다룰 수도 있습니다. 예를 들어, 주어진 행렬에서 0과 1의 구조가 달라지는 경우, 또는 주어진 조건을 만족하는 다른 형태의 정사각형이나 직사각형을 찾아야 할 경우 등 다양한 문제 유형이 존재합니다.

더 나아가기

더 많은 알고리즘 문제를 풀어보고, 시간 복잡도, 공간 복잡도 등을 고려하여 최적화하는 연습을 계속하세요. 이 과정에서 자주 사용하는 자료구조와 알고리즘을 깊이 있게 학습하는 것도 매우 중요합니다. 또한, 다양한 문제를 접하다 보면 자연스럽게 문제 해결 능력이 향상될 것입니다.

앞으로도 많은 알고리즘 강좌를 통해 여러분의 코딩 실력을 함께 키워나가길 바랍니다!

파이썬 코딩테스트 강좌, 가장 빠른 버스 노선 구하기

본 강좌에서는 실제 취업 시험에서 자주 출제되는 알고리즘 문제 중 하나인 가장 빠른 버스 노선 구하기 문제를 다룹니다. 이 문제는 그래프 이론과 최단 경로 알고리즘을 활용하여 해결할 수 있습니다. 과정을 통해 알고리즘 문제 해결 능력을 강화하고, 파이썬 코드를 작성하는 데 필요한 다양한 기술을 익히도록 하겠습니다.

문제 설명

도시 N이 있으며, 1번에서 N번까지의 정점이 있습니다. 각 정점 사이에 여러 개의 버스 노선이 있으며, 버스 노선은 출발과 도착 정점, 소요 시간을 가지고 있습니다. 주어진 정보를 바탕으로, 1번 정점에서 N번 정점까지의 가장 빠른 경로와 그 소요 시간을 구하시오.

입력 형식

  • 첫 번째 줄에 정점의 개수 N (1 ≤ N ≤ 1000)과 버스 노선의 개수 M (1 ≤ M ≤ 10000) 이 주어집니다.
  • 그 다음 M 줄에 각 버스 노선의 정보가 u v w 형식으로 주어지며, u에서 v로 가는 버스의 소요 시간 w (1 ≤ w ≤ 10000)가 주어집니다.

출력 형식

  • 1번 정점에서 N번 정점까지 가는 가장 빠른 소요 시간을 출력합니다. 만약 경로가 없으면 -1을 출력합니다.

문제 해결 과정

1. 문제 이해

이 문제는 최단 경로를 찾는 문제로, 그래프 문제의 대표적인 유형입니다. 버스 노선을 그래프로 표현했을 때, 각 정점은 정류소에 해당하고, 간선은 버스 노선, 간선의 가중치는 소요 시간으로 생각할 수 있습니다. 우리가 해결하고자 하는 것은 1번 정점에서 N번 정점까지 가장 빠르게 이동하는 방법입니다.

2. 알고리즘 선택

최단 경로를 구하는 알고리즘은 여러 가지가 있지만, 여기서는 다익스트라 알고리즘을 사용할 것입니다. 다익스트라 알고리즘은 음의 가중치가 없는 그래프에서 최단 경로를 찾는 데 효율적입니다. 주어진 버스 노선의 소요 시간이 모두 양수이므로 이 알고리즘이 적합합니다.

3. 알고리즘 구현

다익스트라 알고리즘의 기본 아이디어는 각 정점까지의 최단 경로 거리를 기록하는 배열을 유지하면서, 현재 가장 짧은 거리의 정점을 선택해가는 방식입니다. 구체적인 구현 과정은 다음과 같습니다.

# 필요한 라이브러리 import
import sys
import heapq

def dijkstra(N, edges):
    # 초기 거리 배열 설정
    distance = [float('inf')] * (N + 1)
    distance[1] = 0  # 시작점인 1번 정점의 거리는 0
    priority_queue = [(0, 1)]  # (거리, 정점)

    # 그래프 초기화
    graph = [[] for _ in range(N + 1)]
    for u, v, w in edges:
        graph[u].append((v, w))

    while priority_queue:
        current_distance, current_vertex = heapq.heappop(priority_queue)
        
        if current_distance > distance[current_vertex]:
            continue

        for neighbor, weight in graph[current_vertex]:
            distance_via_neighbor = current_distance + weight
            
            if distance_via_neighbor < distance[neighbor]:
                distance[neighbor] = distance_via_neighbor
                heapq.heappush(priority_queue, (distance_via_neighbor, neighbor))

    return distance[N] if distance[N] != float('inf') else -1

# 입력 받기
N, M = map(int, input().split())
edges = [tuple(map(int, input().split())) for _ in range(M)]
result = dijkstra(N, edges)

print(result)

4. 예제 및 테스트 케이스

이 알고리즘의 적절함을 확인하기 위해, 여러 가지 입력 예제를 생각해보겠습니다.

예제 1

입력:
4 5
1 2 1
1 3 4
2 3 2
3 4 1
2 4 5

출력:
3

설명: 1번 정점에서 4번 정점까지의 최단 경로는 1 → 2 → 3 → 4로, 총 소요 시간은 3입니다.

예제 2

입력:
3 3
1 2 1
1 3 4
3 2 2

출력:
-1

설명: 1번 정점에서 2번 정점으로 도달할 수 있는 경로가 없으므로 -1을 출력합니다.

마무리

이번 강좌를 통해, 최단 경로를 구하는 다익스트라 알고리즘을 이용하여 가장 빠른 버스 노선 구하기 문제를 해결하는 방법을 배웠습니다. 알고리즘을 이해하고 구현하는 데 도움이 되셨기를 바랍니다. 앞으로의 코딩 테스트에서도 이러한 문제를 접할 수 있으므로 지속적으로 연습하시길 권장합니다.

파이썬 코딩테스트 강좌, 가장 길게 증가하는 부분 수열 찾기

이 강좌에서는 파이썬 코딩테스트의 중요한 개념 중 하나인 “가장 길게 증가하는 부분 수열” (Longest Increasing Subsequence, LIS)을 찾는 문제를 다룰 것입니다. 이 문제는 여러 IT 기업의 코딩 알고리즘 시험에 자주 등장하며, 효율적인 알고리즘 설계와 구현 능력을 요구합니다. 따라서 제대로 이해하고 연습하는 것이 중요합니다.

1. 문제 설명

주어진 수열에서 증가하는 부분 수열의 길이 중 가장 긴 것을 찾는 문제입니다. 부분 수열은 원래 수열에서 일부 원소들을 선택하여 순서를 유지하면서 만드는 수열입니다. 예를 들어, 수열 [10, 20, 10, 30, 20, 50]이 주어질 때, 가장 긴 증가하는 부분 수열은 [10, 20, 30, 50]로 길이는 4입니다.

2. 문제 접근 및 이해

가장 긴 증가하는 부분 수열 문제는 다음과 같은 특징을 가지고 있습니다.

  • 부분 수열의 원소는 반드시 원래 수열에서 순서를 유지해야 합니다.
  • 부분 수열의 길이를 찾아야 하며, 부분 수열 자체를 찾아야 하는 것은 아닙니다.

이 문제를 해결하기 위해서는 두 가지 접근 방법을 사용할 수 있습니다.

  1. 동적 프로그래밍(Dynamic Programming) 접근법
  2. 이진 탐색(Binary Search) 접근법

2.1 동적 프로그래밍 접근법

동적 프로그래밍을 이용하면 수열의 각 원소를 기준으로 가장 긴 증가하는 부분 수열의 길이를 유지할 수 있습니다. 이 접근법의 시간 복잡도는 O(n^2)입니다.

동적 프로그래밍을 이용한 알고리즘을 다음과 같이 설명할 수 있습니다:

  1. dp[i]를 증가하는 부분 수열의 길이로 초기화하여 모든 값을 1로 설정합니다.
  2. 각 원소 i에 대해 이전 원소 j (j < i)를 순회하면서, arr[j] < arr[i]인 경우 dp[i]를 dp[j] + 1로 업데이트합니다.
  3. 최종 결과는 dp 배열의 최대값입니다.

2.2 이진 탐색 접근법

이진 탐색을 이용한 방법은 좀 더 효율적이며, 시간 복잡도는 O(n log n)입니다. 이 방법은 ‘tails’라는 배열을 이용하여 현재까지의 가장 긴 증가하는 부분 수열의 끝 원소를 저장합니다.

이진 탐색 접근법의 알고리즘을 다음과 같이 설명할 수 있습니다:

  1. 빈 배열을 초기화합니다.
  2. 수열을 순회하면서 현재 원소에 대해 이진 탐색을 수행하여 tails 배열에서 현재 원소를 삽입할 위치를 찾습니다.
  3. 찾은 위치가 tails 배열의 길이와 같다면, 현재 원소를 추가하고 그렇지 않다면 해당 위치를 현재 원소로 업데이트합니다.
  4. 최종 결과는 tails의 길이입니다.

3. 알고리즘 구현

3.1 동적 프로그래밍 구현

def longest_increasing_subsequence(arr):
    n = len(arr)
    dp = [1] * n  # 초기화
    for i in range(n):
        for j in range(i):
            if arr[j] < arr[i]:
                dp[i] = max(dp[i], dp[j] + 1)
    return max(dp)

3.2 이진 탐색 구현

from bisect import bisect_left

def longest_increasing_subsequence(arr):
    tails = []
    for x in arr:
        i = bisect_left(tails, x)  # x보다 큰 원소의 인덱스 찾기
        if i == len(tails):
            tails.append(x)  # 새로운 원소 추가
        else:
            tails[i] = x  # 원소 업데이트
    return len(tails)

4. 예제와 결과

이제 위에서 구현한 알고리즘을 통해 몇 가지 예제를 돌려보겠습니다.

arr = [10, 20, 10, 30, 20, 50]
print(longest_increasing_subsequence(arr))  # 출력: 4

arr = [3, 2, 5, 6, 3, 7, 1]
print(longest_increasing_subsequence(arr))  # 출력: 5

arr = [1, 2, 3, 4, 5]
print(longest_increasing_subsequence(arr))  # 출력: 5

5. 결론

가장 길게 증가하는 부분 수열 찾기 문제는 코딩 인터뷰에서 자주 등장하는 문제로, 동적 프로그래밍과 이진 탐색 두 가지의 접근법을 통해 해결할 수 있습니다. 이 문제를 통해 동적 프로그래밍의 개념과 이진 탐색의 활용을 모두 익힐 수 있으며, 복잡한 알고리즘 문제를 풀기 위한 기초를 다질 수 있습니다.

여기까지 가장 길게 증가하는 부분 수열을 찾는 파이썬 코딩테스트 강좌를 마치겠습니다. 알고리즘 문제를 해결하는 데 도움이 되었길 바랍니다. 지속적인 연습을 통해 알고리즘 실력을 향상시키고, 다음 코딩 테스트에 대비하세요!