Do.

2019 KAKAO BLIND RECRUITMENT - 오픈 채팅방, Swift 본문

Algorithm

2019 KAKAO BLIND RECRUITMENT - 오픈 채팅방, Swift

Hey_Hen 2022. 3. 13. 00:21

https://programmers.co.kr/learn/courses/30/lessons/42888

 

코딩테스트 연습 - 오픈채팅방

오픈채팅방 카카오톡 오픈채팅방에서는 친구가 아닌 사람들과 대화를 할 수 있는데, 본래 닉네임이 아닌 가상의 닉네임을 사용하여 채팅방에 들어갈 수 있다. 신입사원인 김크루는 카카오톡 오

programmers.co.kr

1. 핵심은 출입로그 메시지에서 이름이 변경된 유저의 로그 내용을 변경해야 한다는 뜻이다. 일일이 서치해서 지우기에는 입력 받는데 O(N), 출력문으로 컨버팅 하는데 O(N) 으로 O(N^2)이므로 여유가 없다. 따라서 User를 클래스로 정의하고, 참조를 통해 해결해 볼 수 있다.

2. User는 id로 구분 가능한 Hashable 객체이다.

3. Chat 클래스는 Log 형태로 User를 소유하고 있고, Enter, Leave, Change 명령어를 수행할 때 이름을 참조해서 바꾸기 때문에, 별도의 시간 소모 없이 수행이 가능하다.

import Foundation

final class User: Equatable, Hashable {
  let id: String
  var name: String

  init(id: String, name: String) {
    self.id = id
    self.name = name
  }

  static func == (lhs: User, rhs: User) -> Bool {
    lhs === rhs
  }

  func hash(into hasher: inout Hasher) {
    hasher.combine(id)
  }
}

final class Chat {

  enum Log: CustomStringConvertible {
    case enter(User)
    case leave(User)

    private func messageFormatter(log: Log) -> String {
      switch log {
        case .enter(let user):
          return "\(user.name)님이 들어왔습니다."
        case .leave(let user):
          return "\(user.name)님이 나갔습니다."
      }
    }

    var description: String {
      messageFormatter(log: self)
    }
  }

  private var log: [Log] = []

  private var userList: [String: User] = [:]

  var message: [String] {
    log.map{$0.description}
  }

  func enter(user: User) {
    if let alreadyUser = userList[user.id] {
      log.append(.enter(alreadyUser))
      alreadyUser.name = user.name
    } else {
      log.append(.enter(user))
      userList.updateValue(user, forKey: user.id)
    }
  }

  func leave(userId: String) {
    guard let user = userList[userId] else { return}
    log.append(.leave(user))
  }

  func change(userId: String, changeName: String) {
    guard let target = userList[userId] else { return }
    target.name = changeName
  }
}

func solution(_ record:[String]) -> [String] {

  let chat = Chat()

  record.forEach { packet in
    let command = packet.components(separatedBy: " ")
    switch command[0] {
      case "Enter":
        let user = User(id: command[1], name: command[2])
        chat.enter(user: user)
      case "Leave":
        chat.leave(userId: command[1])
      case "Change":
        chat.change(userId: command[1], changeName: command[2])
      default:
        return
    }
  }
  return chat.message
}
Comments