스위프트 코딩테스트 강좌, 다각형의 면적 구하기

1. 문제 정의

이번 시간에는 주어진 다각형의 면적을 구하는 문제를 다루어보겠습니다. 다각형의 꼭지점이 주어졌을 때, 이를 이용해 면적을 계산하는 알고리즘을 구현합니다. 면적 계산에 사용할 알고리즘은 슈트라센 알고리즘을 기반으로 합니다.

2. 문제 입력

함수는 다음과 같은 형태를 가집니다:

func polygonArea(vertices: [(Double, Double)]) -> Double

여기서 vertices는 다각형의 각 꼭지점을 나타내는 튜플의 배열입니다. 각 튜플은 x, y 좌표를 담고 있습니다.

3. 알고리즘 설명

다각형의 면적을 계산하기 위해, 우리는 다각형 넓이 공식을 사용할 것입니다. 이 공식은 다음과 같습니다:

Area = 0.5 * | Σ (xi * yi+1 - yi * xi+1) |

여기서 i는 0부터 n-1까지의 인덱스를 나타내며, 마지막 꼭지점은 첫 번째 꼭지점과 연결됩니다. 이 공식을 코딩하기 위해서는 다음 단계를 따릅니다:

  1. 꼭지점 수 n을 구합니다.
  2. 각 꼭지점에 대해 면적 기여도를 계산합니다.
  3. 모든 기여도를 더합니다.
  4. 결과를 절대값으로 변환한 후 0.5를 곱합니다.

4. 코드 구현

이제 위 알고리즘을 스위프트 언어로 구현해보겠습니다. 다음은 전체 코드입니다:

func polygonArea(vertices: [(Double, Double)]) -> Double {
    var area = 0.0
    let n = vertices.count

    for i in 0..

4.1 코드 설명

위 코드는 다음과 같이 동작합니다:

  • 먼저 area 변수를 초기화하여 면적을 계산할 준비를 합니다.
  • n은 다각형의 꼭지점 개수를 저장합니다.
  • 각 꼭지점 i에 대해 다음 꼭지점 j를 계산합니다 (여기서 j(i + 1) % n로 설정하여 마지막 꼭지점이 첫 번째 꼭지점과 연결되도록 합니다).
  • 면적 기여도를 계산하여 area에 누적합니다.
  • 루프가 끝나면 면적의 절대값을 2로 나누어 결과를 반환합니다.

5. 테스트 케이스

이제 이 함수를 다양한 테스트 케이스로 검증해보겠습니다. 몇 가지 예시를 들어보겠습니다:

let example1 = [(0.0, 0.0), (4.0, 0.0), (4.0, 3.0), (0.0, 4.0)]
let area1 = polygonArea(vertices: example1)
print(area1) // 12.0

let example2 = [(1.0, 1.0), (3.0, 1.0), (3.0, 3.0), (1.0, 3.0)]
let area2 = polygonArea(vertices: example2)
print(area2) // 4.0

let example3 = [(0.0, 0.0), (5.0, 0.0), (5.0, 5.0), (0.0, 5.0)]
let area3 = polygonArea(vertices: example3)
print(area3) // 25.0

6. 마무리

이번 강좌에서 우리는 스위프트를 사용하여 다각형의 면적을 구하는 알고리즘을 구현했습니다. 다양한 테스트 케이스를 통해 알고리즘이 올바르게 작동하는지 확인했습니다. 이러한 문제를 통해 데이터 구조와 알고리즘에 대한 이해를 깊게 할 수 있으며, 향후 코딩 테스트에서도 유용하게 활용될 것입니다.

다각형과 관련된 더욱 복잡한 문제나 다양한 유형의 면적 계산이 필요할 경우, 이 알고리즘을 바탕으로 추가적인 최적화 및 확장을 고려할 수 있습니다. 다음 강좌에서는 이러한 고급 기술에 대해 다뤄보겠습니다.

스위프트 코딩테스트 강좌, 너비 우선 탐색

1. 서론

너비 우선 탐색(Breadth-First Search, BFS)은 그래프나 트리 구조에서 노드를 탐색하는 알고리즘입니다.
BFS는 시작 노드에서 인접한 노드들을 먼저 탐색한 뒤 해당 노드의 인접 노드를 탐색하는 방식으로,
모든 수준의 노드를 차례대로 방문합니다. 이 과정은 그래프나 트리를 레벨 단위로 탐색하기 때문에
최단 경로를 찾는 데 유용하며, 많은 문제에서 BFS를 활용할 수 있습니다.

2. 문제 설명

문제: 최단 경로 찾기

주어진 2차원 격자에는 세 가지 요소가 존재합니다:

  • 0: 통행 가능한 영역
  • 1: 장애물
  • 2: 출발점
  • 3: 도착점

격자 내에서 출발점(2)에서 도착점(3)까지의 최단 경로를 찾고,
그 경로를 따라 이동하는 데 필요한 최소의 이동 횟수를 출력하는 문제입니다.
만약 도착점에 도달할 수 없는 경우 -1을 출력하세요.

입력 형식

        4 4
        0 0 1 0
        0 1 0 0
        2 0 1 0
        0 0 3 0
        

출력 형식

        7
        

위 예시에서 출발점에서 도착점까지의 최소 이동 횟수는 7입니다.

3. 문제 분석

이 문제를 해결하기 위해 BFS를 사용할 수 있습니다.
BFS는 최단 경로를 찾기에 적합한 알고리즘으로, 주어진 격자에서 출발점(2)에서 시작하여
인접한 통행 가능한 영역(0)으로 이동하면서 도착점(3)까지의 경로를 탐색합니다.
이동할 수 있는 방향은 상, 하, 좌, 우 네 가지로 제한됩니다.

BFS의 특징 중 하나는 각 노드를 큐에 추가하기 때문에 레벨 순서대로 탐색하게 됩니다.
따라서 특정 노드에 도달할 때까지의 이동 횟수를 쉽게 카운트할 수 있습니다.
이 방식을 통해 격자를 채운 모든 0과 3을 탐색하면서 도착점에 도달할 수 있는지 확인할 수 있습니다.

4. 알고리즘 설계

1. **격자 및 객체 초기화**: 입력받은 격자를 기반으로 너비 우선 탐색을 위한 큐와 방문 배열을 초기화합니다.
2. **큐에 시작점 추가**: 출발점을 큐에 추가하고 방문 배열을 업데이트합니다.
3. **BFS 수행**: 큐에서 노드를 하나씩 꺼내며, 그 노드의 상하좌우 이웃을 확인합니다.
이웃이 통행 가능한 경우 큐에 추가하고 방문 처리합니다.
4. **도착점 도달 확인**: 도착점에 도달하면 해당 때의 이동 횟수를 출력합니다.
5. **도달 불가능 시 처리**: 큐가 비어도 도착점에 도달하지 못했을 경우 -1을 출력합니다.

5. 코드 구현

이제 위의 알고리즘 설계를 바탕으로 Swift 언어로 BFS를 구현해보겠습니다.


import Foundation

func findShortestPath(grid: [[Int]], start: (Int, Int), end: (Int, Int)) -> Int {
    let directions = [(1, 0), (-1, 0), (0, 1), (0, -1)]
    var queue: [(Int, Int, Int)] = [(start.0, start.1, 0)] // (x, y, distance)
    var visited = grid
    visited[start.0][start.1] = 1 // 방문 처리

    while !queue.isEmpty {
        let (x, y, distance) = queue.removeFirst()
        
        // 도착점에 도달했을 경우
        if (x, y) == end {
            return distance
        }

        // 이웃 노드 탐색
        for direction in directions {
            let newX = x + direction.0
            let newY = y + direction.1
            
            // 유효 범위 내에 있으며 통행 가능한 경우
            if newX >= 0, newY >= 0, newX < grid.count, newY < grid[0].count, visited[newX][newY] == 0 {
                queue.append((newX, newY, distance + 1))
                visited[newX][newY] = 1 // 방문 처리
            }
        }
    }
    
    // 도착점에 도달하지 못한 경우
    return -1
}

// 예시 입력
let grid: [[Int]] = [
    [0, 0, 1, 0],
    [0, 1, 0, 0],
    [2, 0, 1, 0],
    [0, 0, 3, 0]
]

if let start = grid.enumerated().flatMap({ $0.element.enumerated().compactMap { $1 == 2 ? ($0.offset, $0.element) : nil } }).first,
   let end = grid.enumerated().flatMap({ $0.element.enumerated().compactMap { $1 == 3 ? ($0.offset, $0.element) : nil } }).first {
    let result = findShortestPath(grid: grid, start: start, end: end)
    print(result) // 최소 이동 횟수 출력
}

6. 코드 설명

위의 코드는 주어진 격자에서 출발점과 도착점을 찾은 후,
너비 우선 탐색을 수행하여 최단 경로를 찾습니다.

  • 조사하기 위한 방향은 상, 하, 좌, 우의 4가지 방향을 정의하였습니다.
  • 겹치지 않는 노드를 처리하기 위해 visited 배열을 사용하여
    이미 방문한 노드는 더 이상 큐에 추가하지 않도록 하였습니다.
  • 도착점에 도달할 시 현재까지의 이동 거리를 반환하게 되어 있습니다.
  • 만약 도착점에 도달할 수 없다면 -1을 반환하도록 처리하였습니다.

7. 결론

너비 우선 탐색(BFS)은 최단 경로 탐색 문제를 해결하는 데 매우 유용한 알고리즘입니다.
특히 2차원 격자와 같은 구조에서 효율적으로 동작하며,
여러 프로그래밍 문제에서 빈번하게 등장합니다. 알고리즘의 이해와 문제 해결 능력을 기르기 위해
다양한 유형의 BFS 문제를 연습하는 것이 중요합니다.
이번 강좌를 통해 BFS의 기본 원리를 이해하고 실제 문제를 해결하는 방법을 학습하셨기를 바랍니다.

8. 추가 연습 문제

다음과 같은 변형 문제를 도전해보세요:

  • 주어진 격자에서 장애물(1)을 피해 특정 경로만을 이용해 도착점까지 가기.
  • 다수의 출발점과 도착점 사이의 최단 경로를 구하는 문제.
  • 격자에서 이동하는 대신, 대각선 방향으로도 이동 가능한 경우의 최단 경로 탐색.

이러한 문제들을 통해 너비 우선 탐색 알고리즘에 대한 추가적인 이해와 문제 해결 능력을
더욱 향상시킬 수 있을 것입니다.

스위프트 코딩테스트 강좌, 내림차순으로 자릿수 정렬하기

이 글에서는 스위프트를 이용하여 특정 문제를 해결하는 방법에 대해 알아보겠습니다. 주제는 내림차순으로 자릿수 정렬하기 입니다. 이 문제를 통해 문자열 처리, 정렬 알고리즘, 그리고 스위프트의 자료형 다루기 연습을 할 수 있습니다.

문제 설명

주어진 정수 배열이 있을 때, 각 정수를 문자열로 변환한 다음, 자릿수를 내림차순으로 정렬하여 결과를 반환하는 함수를 작성하세요. 예를 들어, 배열이 [321, 123, 456]이라면, 각 정수를 문자열로 변환하여 ["321", "123", "456"]로 만들고, 이를 내림차순으로 정렬하여 ["321", "456", "123"]를 반환해야 합니다.

문제 예시

  • 입력: [321, 123, 456] → 출력: ["321", "456", "123"]
  • 입력: [12, 345, 7, 89] → 출력: ["89", "7", "345", "12"]
  • 입력: [10, 2, 1] → 출력: ["2", "10", "1"]

문제 접근법

이 문제를 푸는 과정은 다음과 같은 단계로 나눌 수 있습니다:

  1. 정수를 문자열로 변환합니다.
  2. 문자열을 자릿수를 기준으로 내림차순으로 정렬합니다.
  3. 정렬된 결과를 반환합니다.

1단계: 정수 배열을 문자열 배열로 변환하기

어떤 정수를 문자열로 변환하기 위해서는 스위프트의 String() 초기화를 사용할 수 있습니다. 이를 통해 배열 내 모든 정수를 문자열로 변환합니다. 이러한 변환은 map() 함수를 사용하여 쉽게 수행할 수 있습니다.

2단계: 문자열을 내림차순으로 정렬하기

문자열을 정렬할 때는 sorted(by:) 메소드를 이용하여 사용자 정의 정렬 로직을 제공해야 합니다. 이때, 각 문자열의 길이를 비교하거나, 길이가 같을 경우 사전식(lexicographical)으로 비교하는 방법을 사용할 수 있습니다.

3단계: 정렬된 결과 반환하기

정렬이 완료된 문자열 배열을 결과로 반환하면 됩니다. 최종 구현은 다음과 같은 형태가 될 것입니다.

스위프트 코드 구현

func sortDigitsDescending(_ numbers: [Int]) -> [String] {
        // 1단계: 정수를 문자열로 변환
        let stringNumbers = numbers.map { String($0) }
        
        // 2단계: 문자열을 내림차순으로 정렬 (자릿수 우선)
        let sortedNumbers = stringNumbers.sorted { 
            (lhs, rhs) in
            if lhs.count != rhs.count {
                return lhs.count > rhs.count // 자릿수 비교
            } else {
                return lhs > rhs // 자릿수가 같을 경우 값 비교
            }
        }
        
        // 3단계: 정렬된 결과 반환
        return sortedNumbers
    }

코드 설명

위의 스위프트 함수는 다음과 같은 방식으로 작동합니다:

  • numbers.map { String($0) }: 주어진 정수 배열의 각 원소를 문자열로 변환합니다.
  • sorted { ... }: 사용자 정의 정렬 로직을 적용하여 내림차순으로 정렬합니다. 자릿수가 다르다면 자릿수를 우선하여 비교하고, 같다면 문자열의 값을 비교합니다.
  • 정렬된 문자열 배열을 반환하여 결과를 출력합니다.

테스트 케이스

함수가 제대로 작동하는지 확인하기 위해 몇 가지 테스트 케이스를 실행해 볼 수 있습니다. 아래는 해당 함수를 활용한 몇 가지 테스트 코드 예시입니다.

let testCase1 = [321, 123, 456]
let result1 = sortDigitsDescending(testCase1)
print(result1) // ["321", "456", "123"]

let testCase2 = [12, 345, 7, 89]
let result2 = sortDigitsDescending(testCase2)
print(result2) // ["89", "7", "345", "12"]

let testCase3 = [10, 2, 1]
let result3 = sortDigitsDescending(testCase3)
print(result3) // ["2", "10", "1"]

결론

이번 글에서는 스위프트로 정수를 문자열로 변환한 후 자릿수를 기준으로 내림차순으로 정렬하는 문제를 다뤄보았습니다. 문자열 처리 및 정렬 알고리즘에 대한 이해를 높이는 데 유용한 연습이었습니다. 이와 같은 문제들은 코딩 테스트에서 자주 출제되며 실전에서 유용하게 활용될 수 있습니다.

코드 구현 과정을 통해 스위프트의 다양한 기능을 활용할 수 있으며, 문제 해결 능력을 향상하는 데 큰 도움이 되기를 바랍니다. 다음 강좌에서도 더욱 흥미로운 문제를 다루어 보겠습니다!

스위프트 코딩테스트 강좌, 깊이 우선 탐색

본 강좌에서는 깊이 우선 탐색(DFS, Depth-First Search) 알고리즘을 사용하여 알고리즘 문제를 해결하는 방법을 설명합니다. 이 글에서는 실제 알고리즘 문제를 다루고, 그 문제를 해결하기 위한 과정과 코드를 자세히 설명하겠습니다.

문제 설명

주어진 이진 트리에서 모든 경로의 합을 구하기를 원합니다. 각 경로는 루트에서 리프 노드까지의 경로입니다. 이진 트리는 다음과 같은 형태로 주어집니다:

        class TreeNode {
            var val: Int
            var left: TreeNode?
            var right: TreeNode?

            init(_ val: Int) {
                self.val = val
                self.left = nil
                self.right = nil
            }
        }
        

여기서 각 노드는 값(val)을 가지고 있으며, 왼쪽 자식(left)과 오른쪽 자식(right)으로 이어져 있습니다. 만약 다음과 같은 이진 트리가 주어진다면:

               1
              / \
             2   3
            / \
           4   5
        

루트 노드 1에서 시작하여 리프 노드 4와 5까지의 경로의 합은 7(1+2+4)과 8(1+2+5)이 되므로, 최종 답은 15가 됩니다.

문제 접근 방법

이 문제를 해결하기 위해 DFS 알고리즘을 사용할 것입니다. DFS는 특정 노드에서 시작하여 가능한 한 깊숙이 노드를 탐색하고, 더 이상 갈 수 없게 되면 돌아오는 방식으로 작동합니다. 이 경우, 우리는 각 경로의 누적 합을 계산하면서 리프 노드에 도달했을 때 그 합을 기록할 것입니다.

문제를 해결하기 위한 단계는 다음과 같습니다:

  1. 루트 노드에서 시작하여 DFS를 수행합니다.
  2. 현재 노드의 값(val)을 누적 합에 더합니다.
  3. 현재 노드가 리프 노드인 경우, 누적 합계를 결과에 추가합니다.
  4. 리프 노드가 아닌 경우, 왼쪽 자식과 오른쪽 자식으로 나아가 DFS를 재귀적으로 호출합니다.
  5. 모든 경로에 대해 위의 과정을 반복하여 누적 합을 구합니다.

스위프트 코드 구현

이제 스위프트를 사용하여 위의 알고리즘을 코드로 구현해 보겠습니다.

        class TreeNode {
            var val: Int
            var left: TreeNode?
            var right: TreeNode?

            init(_ val: Int) {
                self.val = val
                self.left = nil
                self.right = nil
            }
        }

        class Solution {
            func sumNumbers(_ root: TreeNode?) -> Int {
                return dfs(root, 0)
            }

            private func dfs(_ node: TreeNode?, _ currentSum: Int) -> Int {
                guard let node = node else { return 0 }
                let newSum = currentSum * 10 + node.val

                if node.left == nil && node.right == nil {
                    return newSum
                }

                return dfs(node.left, newSum) + dfs(node.right, newSum)
            }
        }
        

위의 코드는 재귀적으로 DFS를 수행하여 경로의 합계를 계산합니다. sumNumbers 함수는 루트 노드를 인수로 받으며, dfs 함수는 현재 노드와 누적 합을 인수로 받아서 최종 합을 반환합니다. 과정은 다음과 같습니다:

  1. sumNumbers 함수가 호출되면, 현재 누적 합 0으로 DFS를 시작합니다.
  2. 각 노드에 대해, 현재 합을 10배하고 노드 값을 더하여 새로운 합을 생성합니다.
  3. 리프 노드에 도달하면 해당 합을 반환하고, 왼쪽과 오른쪽 자식의 합을 더한 후 최종 결과를 반환합니다.

테스트 케이스

코드가 올바르게 작동하는지 확인하기 위해 몇 가지 테스트 케이스를 생성해보겠습니다. 다음은 다양한 이진 트리 구조에 대한 예입니다.

        let root = TreeNode(1)
        root.left = TreeNode(2)
        root.right = TreeNode(3)
        root.left!.left = TreeNode(4)
        root.left!.right = TreeNode(5)

        let solution = Solution()
        print(solution.sumNumbers(root)) // 출력값: 15
        

위의 테스트 케이스에서는 1에서 시작하여 2를 거쳐 4와 5에 도달하는 모든 경로의 합을 계산합니다. 그 결과, 1-2-4와 1-2-5의 합이 더해져 15가 됩니다.

성과 및 최적화

이 문제에서는 DFS 방법을 사용하여 O(N) 시간 복잡도를 가집니다. 여기서 N은 노드의 수입니다. 공간 복잡도는 O(H)로, H는 트리의 높이입니다. DFS는 스택을 사용하기 때문에 최악의 경우에는 모든 노드를 방문해야 하므로 높이에 비례하는 메모리를 사용하게 됩니다.

이 외에도 BFS(Breadth-First Search) 방법을 사용해 문제를 풀 수도 있지만, 리프 노드까지의 경로의 합을 구하는 문제에서는 DFS가 더 직관적이고 효율적입니다.

결론

이번 강좌에서는 깊이 우선 탐색을 통해 이진 트리에서 리프 노드까지의 경로 합을 구하는 문제를 다뤘습니다. DFS 알고리즘의 개념을 이해하고, 이를 스위프트로 구현해 보았습니다. 이런 문제들은 많은 코딩 테스트에서 자주 출제되므로, 다양한 변형 문제를 통해 더 많은 연습을 해보시길 권장합니다.

이제 기초적인 DFS를 다루었으니, 더 복잡한 문제에 대해 도전해 보세요. 예를 들어, 그래프 탐색, 연결 요소 찾기, 최단 경로 문제 등으로 범위를 확장할 수 있습니다. 연습을 통해 더욱 능숙한 코딩 능력을 갖추시길 바랍니다.

이 글이 여러분의 코드 테스트 준비에 도움이 되었기를 바랍니다. 질문이나 추가적인 댓글이 있다면 아래에 남겨주세요.

스위프트 코딩테스트 강좌, 나머지 합 구하기

최근 들어 소프트웨어 개발 분야에서 알고리즘 코딩 테스트의 중요성이 커지고 있습니다. 많은 기업들이 면접 과정에서 코딩 테스트를 통해 지원자의 문제 해결 능력을 평가하고 있기 때문입니다. 이번 글에서는 스위프트 언어를 사용하여 ‘나머지 합 구하기’ 문제를 풀어보며, 문제 이해부터 해결 과정까지 전반적인 내용을 다뤄보겠습니다.

문제 설명

주어진 정수 배열 nums와 정수 k가 있을 때, nums의 모든 부분 배열에서 그 합을 k로 나눈 나머지를 구하고, 이 나머지의 합을 구하는 함수를 작성하세요. 함수는 나머지의 합을 반환해야 합니다.

문제 예시

  • 입력: nums = [1, 2, 3, 4, 5], k = 3
  • 출력: 10
  • 설명: 부분 배열의 합은 1, 1+2=3, 1+2+3=6, 1+2+3+4=10, ... 등이 있으며, 각각을 3으로 나누고 나머지를 구해야 합니다.

문제 접근 방식

해당 문제를 해결하기 위해서는 먼저 모든 부분 배열을 생성하고, 그 합을 구한 뒤에 k로 나눈 나머지를 구해야 합니다. 그러나 모든 부분 배열을 직접 생성하면 시간 복잡도가 O(n^3) 이상이 될 수 있으므로, 좀 더 효율적인 방법이 필요합니다.

우리는 부분 배열의 합을 누적하여 구하고, 이를 활용하여 문제를 해결할 수 있습니다. 이 과정에서 나머지를 저장하는 방법을 생각해볼 수 있습니다.

스위프트 구현


func subarraySumRemainder(nums: [Int], k: Int) -> Int {
    var totalRemainderSum = 0
    let n = nums.count
    
    for start in 0..

코드 설명

위의 함수 subarraySumRemaindernumsk를 입력받아 나머지 합을 계산하는 함수입니다.

  • totalRemainderSum: 모든 부분 배열의 나머지 합을 저장하는 변수입니다.
  • n: 배열의 크기를 저장합니다.
  • for start in 0..: 각 부분 배열의 시작 인덱스를 설정합니다.
  • currentSum: 현재 부분 배열의 합을 저장합니다.
  • for end in start..: 부분 배열의 끝 인덱스를 설정하고, 현재 합을 업데이트합니다.
  • totalRemainderSum += currentSum % k: 나머지를 계산하여 총합에 추가합니다.

시간 복잡도 분석

이 알고리즘의 시간 복잡도는 O(n^2)입니다. 이는 최악의 경우 배열의 모든 부분 배열을 순회해야 하기 때문입니다. 나머지 합을 구하는 것은 상수 시간에 가능하기 때문에, 총 복잡도는 부분 배열을 생성하는 데 소요되는 시간에 의해 결정됩니다.

다른 접근법

다양한 방법으로 이 문제를 해결할 수 있습니다. 예를 들어, prefix sum 기술을 사용하면, 더 나은 시간 복잡도를 얻을 수 있습니다. prefix sum을 사용하면 특정 범위의 합을 빠르게 구할 수 있기 때문에, 나머지를 계산하는 시간을 단축할 수 있습니다.

Prefix Sum을 이용한 방법


func subarraySumRemainderUsingPrefixSum(nums: [Int], k: Int) -> Int {
    var prefixSums = [Int](repeating: 0, count: nums.count + 1)
    for i in 1...nums.count {
        prefixSums[i] = prefixSums[i - 1] + nums[i - 1]
    }
    
    var totalRemainderSum = 0
    for start in 0..

결론

이번 글에서는 스위프트 언어를 사용하여 ‘나머지 합 구하기’ 문제를 해결하는 방법을 살펴보았습니다. 문제를 이해하고 접근하는 과정부터 구현, 시간 복잡도 분석까지 종합적으로 설명했습니다. 알고리즘 문제는 다양한 접근법이 있으며, 문제를 해결하기 위한 창의적인 생각을 요구합니다. 꾸준한 연습을 통해 여러분의 코딩 능력을 키워나가시길 바랍니다.

참고 자료

  • LeetCode (https://leetcode.com)
  • GeeksforGeeks (https://www.geeksforgeeks.org)
  • Algorithm Visualizer (https://algorithm-visualizer.org)