[Programmers] 오픈채팅방(Java) - 시간초과 실패로 깨달은 것

이동기·2024년 10월 2일
1

프로그래머스에서 연습중에 오픈채팅방이라는 문제를 풀어보았습니다.

코드실행 결과는 정상적으로 나왔지만 결과제출에서 25번째 테스트부터 데이터량이 커지더니 시간초과 실패를 했습니다..ㅠ
채팅 상태 관련 객체를 만들어서 풀었는데 객체가 생기니 필요없고 비효율적인 문법이나 데이터 가공처리 로직이 들어갔고 거기서 시간이 오래걸린 것 같습니다.

평소 일할때는 애초에 관련된 객체가 만들어져 있는경우가 많으니 그것에 익숙해져 너무 매몰되어있었던것 같습니다. 강박적으로 객체를 만들고 String 값을 코드에 하드코딩하는 것에 대한 거부감이 있었던게 패착이었고 문제를 너무 편협하게 바라보고 있다는 것을 깨달았습니다.

부끄럽지만 이를 계기로 깨달은 것을 상기하고자 포스팅을 남겼습니다.


나의 코드(시간초과 실패)

import java.util.*;
import java.util.stream.Collectors;

class Solution {
    public String[] solution(String[] record) {
        List<UserChatStatus> userChatStatuses = makeUserChatStatus(record);
        return makeUserChatStatusString(userChatStatuses);
    }

    private static List<UserChatStatus> changeNickName(List<UserChatStatus> userChatStatuses) {
        // 상태가 Leave가 아닌 것만 추출, id 기준 가장 마지막 값만 남김
        List<UserChatStatus> changeTargets = userChatStatuses.stream()
                .filter(user -> user.getStatus() != Status.LEAVE)
                .collect(Collectors.toMap(
                        UserChatStatus::getId,
                        user -> user,
                        (oldValue, newValue) -> newValue
                ))
                .values()                   // Map의 값들만 추출
                .stream()                   // 다시 Stream으로 변환
                .collect(Collectors.toList()); // List로 수집

        // 닉네임 변경
        changeTargets.forEach(changeStatus ->
            userChatStatuses.forEach(target -> {
                if (target.getId().equals(changeStatus.getId())) {
                    target.setNickName(changeStatus.getNickName());
                }
            })
        );

        return userChatStatuses;
    }

    // 결과 배열 생성
    private static String[] makeUserChatStatusString(List<UserChatStatus> userChatStatuses) {
        String[] results = new String[userChatStatuses.size()];
        for (int i = 0; i < userChatStatuses.size(); i++) {
            UserChatStatus target = userChatStatuses.get(i);
            results[i] = target.getNickName() + target.getStatus().getText();
        }

        return results;
    }

    // 채팅 상태 메시지 객체 생성
    private static List<UserChatStatus> makeUserChatStatus(String[] records) {
        List<UserChatStatus> userChatStatuses = new ArrayList<>();
        Map<String, String> nickNameMap = new HashMap<>();

        for (String record: records) {
            String[] recordProperties = record.split(" ");
            nickNameMap.computeIfAbsent(recordProperties[1], k -> recordProperties[2]);

            userChatStatuses.add(new UserChatStatus(
                    recordProperties[1],
                    recordProperties.length == 3 ? recordProperties[2] : nickNameMap.get(recordProperties[1]),
                    Status.valueOf(recordProperties[0].toUpperCase())
            ));
        }

        return changeNickName(userChatStatuses).stream()
                .filter(user -> user.getStatus() != Status.CHANGE)
                .collect(Collectors.toList());
    }
}

class UserChatStatus {
    private final String id;
    private String nickName;
    private final Status status;

    UserChatStatus(String id, String nickName, Status status){
        this.id = id;
        this.nickName = nickName;
        this.status = status;
    }

    public void setNickName(String nickName) {
        this.nickName = nickName;
    }

    public String getId() {
        return this.id;
    }

    public String getNickName() {
        return this.nickName;
    }

    public Status getStatus() {
        return this.status;
    }
}

enum Status {
    ENTER("님이 들어왔습니다."),
    LEAVE("님이 나갔습니다."),
    CHANGE("");

    Status(String text) {
        this.text = text;
    }

    private final String text;

    public String getText(){
        return this.text;
    }
}

타인의 성공한 코드(참고)

import java.util.*;
class Solution {
    public String[] solution(String[] record) {
        Map<String, String> idMap = new HashMap<>(); // (아이디 - 닉네임) Map
        int count = 0; // 메시지에 뿌려지지 않을 경우(Change일 때) 카운트

        for(int i = 0; i < record.length; i++){
            String[] info = record[i].split(" ");

            if(info[0].equals("Leave")){        // 나가는 경우
                continue;
            } else if(info[0].equals("Enter")){ // 들어오는 경우
                idMap.put(info[1], info[2]);
            } else {                            // 닉네임을 변경하는 경우
                idMap.put(info[1], info[2]);
                count++;
            }
        }

        String[] answer = new String[record.length - count];
        int idx = 0;

        for(int i = 0; i < record.length; i++){
            String[] info = record[i].split(" ");
            String nickname = idMap.get(info[1]);

            if(info[0].equals("Enter")){                      // 들어오는 경우
                answer[idx++] = nickname + "님이 들어왔습니다.";
            } else if(info[0].equals("Leave")){               // 나가는 경우
                answer[idx++] = nickname + "님이 나갔습니다.";
            }
        }

        return answer;
    }
}
profile
개발자가 되고 싶은 '개'발자입니다. https://github.com/lee-dong-gi

0개의 댓글