# 99클럽 코테 스터디 12일차 TIL - 게임 참여 인원

피터·2025년 4월 15일
0

오늘의 문제: 25757

민겸이는 친구들과 함께 Y, F, O 세 가지 게임을 하려고 한다. 각 게임별로 필요한 참가자 수가 다르며, 이미 게임을 한 사람과는 다시 게임을 하지 않는다.


🤔 문제 분석 및 초기 접근

이 문제는 N명의 사람들과 게임 종류(Y, F, O)가 주어질 때, 민겸이가 몇 번의 게임을 할 수 있는지 계산하는 문제이다.

처음에는 게임 종류별 필요 인원 수를 다음과 같이 설정했다:

  • Y: 2명 (민겸이 포함)
  • F: 3명 (민겸이 포함)
  • O: 4명 (민겸이 포함)

하지만 처음 접근에서 실수했던 부분은 민겸이를 포함한 인원 수를 계산했다는 점이다. 민겸이는 항상 참여하므로 추가로 필요한 인원은 각각 1명, 2명, 3명이었다.

// 초기 접근 (오류)
init(game: String) {
    let game = Game(rawValue: game)!
    self.capacity = game.capacity
}

💡 핵심 아이디어 및 구현

핵심 아이디어는 다음과 같다:
1. 각 게임 유형별 필요 참가자 수를 정의한다 (민겸이 제외)
2. 이미 게임에 참여한 사람들을 Set을 통해 추적한다
3. 현재 모인 인원이 필요 인원에 도달하면 게임을 진행하고 카운트를 증가시킨다

class GameManager {
    private var array = [String]()
    private var hadGame = Set<String>()
    private var gameCount = 0
    private let capacity: Int
    
    enum Game: String {
        case Y
        case F
        case O
        
        var capacity: Int {
            switch self {
            case .Y:
                return 2
            case .F:
                return 3
            case .O:
                return 4
            }
        }
    }
    
    init(game: String) {
        let game = Game(rawValue: game)!
        self.capacity = game.capacity - 1 // 민겸이를 제외한 필요 인원
    }

    func append(_ name: String) {
        guard !hadGame.contains(name) && !array.contains(name) else { return }
        array.append(name)
        if array.count >= capacity {
            gameCount += 1
            array.forEach { value in
                hadGame.insert(value)
            }
            clear()
        }
    }

    private func clear() {
        array.removeAll()
    }

    func getTotalGameCount() -> Int {
        return gameCount
    }
}

🔄 코드 최적화 및 개선

위의 코드는 정확하게 작동하지만, 더 간결하게 개선할 수 있는 여지가 있다. 아래는 두 가지 최적화 방향이다:

1. 단일 Set 사용 최적화

arrayhadGame 두 개의 컬렉션을 관리하는 것은 불필요한 복잡성을 만들 수 있다. 단일 Set만 사용하여 구현하면 코드가 더 간결해진다:

class GameManager {
    private var participants = Set<String>()
    private let playerPerGame: Int
    
    init(gameType: String) {
        self.playerPerGame = ["Y": 1, "F": 2, "O": 3][gameType] ?? 1
    }
    
    func addPlayer(_ name: String) -> Bool {
        return participants.insert(name).inserted
    }
    
    func getPossibleGameCount() -> Int {
        return participants.count / playerPerGame
    }
}

이 구현에서는:

  • 중복 체크와 저장을 하나의 Set으로 처리
  • dictionary를 사용하여 열거형 없이 게임 유형별 필요 인원수 매핑
  • 실시간으로 게임 카운트를 관리하지 않고, 최종 결과를 계산식으로 간단히 도출

2. 함수형 접근법

클래스를 완전히 제거하고 함수형 접근 방식으로 구현하면 더욱 간결해진다:

func countPossibleGames(players: [String], gameType: String) -> Int {
    let requiredPlayers = ["Y": 1, "F": 2, "O": 3][gameType] ?? 1
    let uniquePlayers = Set(players).count
    return uniquePlayers / requiredPlayers
}

이 방식은:

  • 불필요한 상태 관리 없이 입력과 출력만으로 문제 해결
  • 단 몇 줄의 코드로 동일한 결과 도출
  • 메모리 사용량 감소 및 코드 가독성 향상

위의 두 가지 접근법 모두 기존 구현보다 간결하면서도 동일한 결과를 제공한다. 특히 함수형 접근법은 문제의 본질(중복되지 않는 플레이어들로 가능한 최대 게임 수 계산)에 집중하여 불필요한 복잡성을 제거했다.


✅ 결과 및 회고

처음에는 민겸이가 항상 참여한다는 점을 고려하지 않아 문제를 틀렸지만, 수정 후 정답을 맞출 수 있었다. 이 문제를 통해 문제를 꼼꼼히 읽고 조건을 정확히 파악하는 것의 중요성을 다시 한번 느꼈다.

또한 코드를 점진적으로 개선하면서, 동일한 문제를 더 간결하고 효율적으로 해결할 수 있는 여러 방법이 있음을 배웠다.

시간 복잡도: O(N), 여기서 N은 입력받은 사람의 수
공간 복잡도: O(N), Set에 저장되는 사람의 수


✨ 오늘 배운 점 정리

  • Set 자료구조를 활용하여 중복 참여자를 효율적으로 관리하는 방법
  • 문제의 조건을 정확히 파악하는 것의 중요성
  • 열거형(enum)을 활용하여 관련된 상수 값을 정리하는 기법
  • 코드 리팩토링을 통해 더 간결하고 읽기 쉬운 코드를 작성하는 방법
  • 클래스 기반 구현과 함수형 접근법의 차이점 및 각각의 장단점

profile
iOS 개발자입니다.

0개의 댓글