catsridingCATSRIDING|OCEANWAVES
Challenges

프로그래머스 | Level 2 | 오픈채팅방

jynn@catsriding.com
Aug 27, 2024
Published byJynn
999
프로그래머스 | Level 2 | 오픈채팅방

Programmers | Level 2 | 오픈채팅방

Problems

󰧭 Description

오픈채팅방에서 사용자의 입장과 퇴장, 그리고 닉네임 변경과 관련된 로그를 분석하여 해당 로그를 바탕으로 채팅방에서 출력될 메시지를 작성하는 문제입니다. 사용자는 고유한 유저 ID를 가지며, 이 ID에 대해 닉네임이 변경될 수 있습니다. 닉네임이 변경되면 과거에 남긴 모든 메시지도 새로운 닉네임으로 갱신되어야 합니다. 로그를 처리한 후, 최종 출력 메시지를 반환해야 합니다.

 Constraints

  • 로그의 길이는 최대 100,000개입니다.
  • 각 사용자는 유저 ID로 구분되며, 닉네임은 변경될 수 있습니다.
  • 기록된 명령어는 Enter, Leave, Change 세 가지입니다.
  • Enter는 사용자가 채팅방에 들어온 것을 의미하고, Leave는 나간 것을 의미합니다.
  • Change는 닉네임을 변경하는 명령어로, 이전 기록된 모든 해당 유저의 메시지도 새로운 닉네임으로 변경됩니다.

󰦕 Examples

recordresult
["Enter uid1234 Muzi", "Enter uid4567 Prodo","Leave uid1234","Enter uid1234 Prodo","Change uid4567 Ryan"]["Prodo님이 들어왔습니다.", "Ryan님이 들어왔습니다.", "Prodo님이 나갔습니다.", "Prodo님이 들어왔습니다."]

Solutions

󰘦 Code

Solution.java
import java.util.*;

class Solution {
    
    private static final String ENTER_MESSAGE = "님이 들어왔습니다.";
    private static final String LEAVE_MESSAGE = "님이 나갔습니다.";
    
    public String[] solution(String[] record) {
        Map<String, String> users = new HashMap<>(); // 유저 ID별 닉네임을 저장하는 해시맵
        List<String[]> logs = new ArrayList<>(); // 각 유저의 입장 및 퇴장 기록을 저장하는 리스트
        
        // 모든 기록을 처리하면서 유저 ID와 닉네임을 맵에 저장하고, 로그를 기록함
        for (int i = 0; i < record.length; i++) {
            String[] parts = record[i].split(" ");
            String action = parts[0];  // 명령어 (Enter, Leave, Change)
            String id = parts[1];  // 유저 ID

            // Enter 명령어 처리: 유저가 입장할 때 닉네임을 갱신하고, 로그를 기록
            if (action.equals("Enter")) {
                users.put(id, parts[2]);  // 닉네임 갱신
                logs.add(new String[]{id, ENTER_MESSAGE});  // 입장 메시지 기록
            }
            // Leave 명령어 처리: 유저가 나갈 때 로그를 기록
            if (action.equals("Leave")) {
                logs.add(new String[]{id, LEAVE_MESSAGE});  // 퇴장 메시지 기록
            }
            // Change 명령어 처리: 닉네임을 갱신하지만 로그는 추가하지 않음
            if (action.equals("Change")) {
                users.put(id, parts[2]);  // 닉네임 갱신
            }
        }
        
        // 로그를 순회하며 각 유저의 최신 닉네임을 반영한 메시지를 생성
        String[] result = new String[logs.size()];
        for (int i = 0; i < logs.size(); i++) {
            String name = users.get(logs.get(i)[0]);  // 최신 닉네임 가져오기
            String message = name + logs.get(i)[1];  // 닉네임 + 메시지 형식으로 조합
            result[i] = message;  // 결과 배열에 저장
        }
        return result;  // 결과 반환
    }
}

 Approach

이 문제는 오픈채팅방에서 유저의 행동을 로그로 기록한 데이터를 처리하고, 각 유저의 행동을 바탕으로 최종 출력 메시지를 생성하는 시뮬레이션 문제입니다. 다음과 같은 방식으로 접근하였습니다.

1. 유저의 닉네임 관리 및 기록 저장

우선 각 사용자의 유저 ID에 따른 닉네임을 관리하기 위해 Map<K, V> 형태의 해시맵을 사용했습니다. 이 맵은 ID를 키로 하여 닉네임을 저장하며, 닉네임이 변경될 때마다 해당 유저의 ID에 매핑된 닉네임을 업데이트합니다.

또한, 유저의 입장과 퇴장 기록을 저장하기 위해 List<String[]> 리스트를 사용하였습니다. 리스트에는 각 행동을 기록하는데, EnterLeave 명령어가 발생할 때마다 유저의 ID와 해당 메시지를 함께 저장합니다. 이를 통해 나중에 각 유저의 최신 닉네임을 반영해 출력 메시지를 생성할 수 있도록 했습니다.

Solution.java
// 유저 ID별 닉네임을 저장하는 해시맵
Map<String, String> users = new HashMap<>();
// 각 유저의 입장 및 퇴장 기록을 저장하는 리스트
List<String[]> logs = new ArrayList<>();
2. 로그 처리

각 기록된 로그는 공백을 기준으로 분열하여 세 가지 행동(Enter, Leave, Change)을 분석합니다.

  • Enter: 유저가 입장할 때 해당 유저의 닉네임을 users 맵에 저장하고, logs 리스트에 입장 기록을 남깁니다.
  • Leave: 유저가 나갔음을 기록하며, 해당 유저의 ID와 나갔다는 메시지를 logs 리스트에 기록합니다.
  • Change: 단순히 해당 유저의 닉네임만 갱신하는 역할을 하며, 채팅방의 메시지에 별도로 영향을 미치지 않습니다.
Solution.java
for (int i = 0; i < record.length; i++) {
    String[] parts = record[i].split(" ");
    String action = parts[0];  // 행동 (Enter, Leave, Change)
    String id = parts[1];  // 유저 ID

    // Enter 처리: 유저가 입장할 때 닉네임을 갱신하고, 로그를 기록
    if (action.equals("Enter")) {
        users.put(id, parts[2]);  // 닉네임 갱신
        logs.add(new String[]{id, ENTER_MESSAGE});  // 입장 메시지 기록
    }
    // Leave 처리: 유저가 나갈 때 로그를 기록
    if (action.equals("Leave")) {
        logs.add(new String[]{id, LEAVE_MESSAGE});  // 퇴장 메시지 기록
    }
    // Change 처리: 닉네임을 갱신하지만 로그는 추가하지 않음
    if (action.equals("Change")) {
        users.put(id, parts[2]);  // 닉네임 갱신
    }
}
3. 최종 메시지 생성

모든 로그가 처리된 후, logs 리스트를 순회하면서 각 유저 ID에 대한 최신 닉네임을 users 맵에서 가져와 로그에 반영합니다. 이를 통해 유저의 모든 기록이 최신 닉네임으로 출력되도록 했습니다.

Solution.java
// 로그를 순회하며 각 유저의 최신 닉네임을 반영한 메시지를 생성
String[] result = new String[logs.size()];
for (int i = 0; i < logs.size(); i++) {
    String name = users.get(logs.get(i)[0]);  // 최신 닉네임 가져오기
    String message = name + logs.get(i)[1];  // 닉네임 + 메시지 형식으로 조합
    result[i] = message;  // 결과 배열에 저장
}
return result;  // 결과 반환

󰄉 Complexity

  • TC: O(n)
  • 💾 SC: O(n)

이 알고리즘은 로그를 두 번 순회하지만, 각각의 작업이 독립적이기 때문에 시간 복잡도는 O(n)으로 효율적입니다. 로그가 100,000개까지 주어질 수 있는 상황에서도 성능 이슈 없이 처리할 수 있습니다.

  • Algorithm
  • Simulation