프로그래머스 | Level 2 | 오픈채팅방
Programmers | Level 2 | 오픈채팅방
Problems
- 📘 Src: Programmers
- 🗂️ Cat: Simulation
Description
오픈채팅방에서 사용자의 입장과 퇴장, 그리고 닉네임 변경과 관련된 로그를 분석하여 해당 로그를 바탕으로 채팅방에서 출력될 메시지를 작성하는 문제입니다. 사용자는 고유한 유저 ID를 가지며, 이 ID에 대해 닉네임이 변경될 수 있습니다. 닉네임이 변경되면 과거에 남긴 모든 메시지도 새로운 닉네임으로 갱신되어야 합니다. 로그를 처리한 후, 최종 출력 메시지를 반환해야 합니다.
Constraints
- 로그의 길이는 최대 100,000개입니다.
- 각 사용자는 유저 ID로 구분되며, 닉네임은 변경될 수 있습니다.
- 기록된 명령어는
Enter
,Leave
,Change
세 가지입니다. Enter
는 사용자가 채팅방에 들어온 것을 의미하고,Leave
는 나간 것을 의미합니다.Change
는 닉네임을 변경하는 명령어로, 이전 기록된 모든 해당 유저의 메시지도 새로운 닉네임으로 변경됩니다.
Examples
record | result |
---|---|
["Enter uid1234 Muzi", "Enter uid4567 Prodo","Leave uid1234","Enter uid1234 Prodo","Change uid4567 Ryan"] | ["Prodo님이 들어왔습니다.", "Ryan님이 들어왔습니다.", "Prodo님이 나갔습니다.", "Prodo님이 들어왔습니다."] |
Solutions
Code
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[]>
리스트를 사용하였습니다. 리스트에는 각 행동을 기록하는데, Enter
와 Leave
명령어가 발생할 때마다 유저의 ID와 해당 메시지를 함께 저장합니다. 이를 통해 나중에 각 유저의 최신 닉네임을 반영해 출력 메시지를 생성할 수 있도록 했습니다.
// 유저 ID별 닉네임을 저장하는 해시맵
Map<String, String> users = new HashMap<>();
// 각 유저의 입장 및 퇴장 기록을 저장하는 리스트
List<String[]> logs = new ArrayList<>();
2. 로그 처리
각 기록된 로그는 공백을 기준으로 분열하여 세 가지 행동(Enter
, Leave
, Change
)을 분석합니다.
Enter
: 유저가 입장할 때 해당 유저의 닉네임을users
맵에 저장하고,logs
리스트에 입장 기록을 남깁니다.Leave
: 유저가 나갔음을 기록하며, 해당 유저의 ID와 나갔다는 메시지를logs
리스트에 기록합니다.Change
: 단순히 해당 유저의 닉네임만 갱신하는 역할을 하며, 채팅방의 메시지에 별도로 영향을 미치지 않습니다.
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
맵에서 가져와 로그에 반영합니다. 이를 통해 유저의 모든 기록이 최신 닉네임으로 출력되도록 했습니다.
// 로그를 순회하며 각 유저의 최신 닉네임을 반영한 메시지를 생성
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