Don't give up!

[프로그래머스] 오픈채팅방(java) 본문

Coding Test/Programmers

[프로그래머스] 오픈채팅방(java)

Heang Lee 2021. 5. 4. 18:38

코딩테스트 연습 - 오픈채팅방 | 프로그래머스 (programmers.co.kr)

 

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

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

programmers.co.kr

어떻게 생각하고 문제를 풀었는가?

입력 받는 문자열들은 모두 "[행동] [유저아이디]" 또는 "[행동] [유저아이디] [닉네임]"으로 이루어져 있습니다.

가장 마지막에 입력된 닉네임으로 메시지에 출력되기 때문에 유저아이디 - 닉네임으로 먼저 저장을 하는 작업을 수행한 후 행동에 따른 메시지를 출력하는 것으로 문제를 해결할 수 있다고 생각하였습니다.

코드

import java.util.Map;
import java.util.HashMap;
import java.util.Stack;
class Solution {
    public String[] solution(String[] record) {
        Map<String, String> nickname = new HashMap<>();
        String[] words = new String[3];
        for(String log : record){
            words = log.split("\\s");
            if(!words[0].equals("Leave")){
                nickname.put(words[1],words[2]);
            }
        }
        Stack<String> answer = new Stack<>();
        for(int i=0; i<record.length; i++){
            words = record[i].split("\\s");
            if(words[0].equals("Enter")){
                answer.push(nickname.get(words[1]) + "님이 들어왔습니다.");
            }else if(words[0].equals("Leave")){
                answer.push(nickname.get(words[1]) + "님이 나갔습니다.");
            }
        }

        return answer.toArray(new String[answer.size()]);
    }
} 

설계를 바탕으로 코드를 작성하였습니다.

String의 split함수에 공백문자를 의미하는 정규표현식을 사용하여 유저아이디와 닉네임을 쉽게 가져올 수 있었습니다.

닉네임 변경은 메시지에 출력되지 않습니다. 따라서 Change의 행동을 출력에 포함시키지 않기 위해 stack을 활용하여 출력되어야 할 메시지들만을 저장한 후 toArray함수로 String 배열이 반환되도록 하였습니다.

 

테스트를 통과하고 난 후 다양한 출력메시지가 변경되어도 쉽게 적용될 수 있도록 코드를 개선해보고자 하였습니다.

개선

import java.util.Map;
import java.util.HashMap;
import java.util.ArrayList;
class Solution {
    private final String FORMAT_ENTER = "%s님이 들어왔습니다.";
    private final String FORMAT_LEAVE = "%s님이 나갔습니다.";
    
    public String[] solution(String[] record) {
        Map<String, String> nickname = new HashMap<>();
        String[] words = new String[3];
        for(String log : record){
            words = log.split("\\s");
            if(!words[0].equals("Leave")){
                nickname.put(words[1],words[2]);
            }
        }
        ArrayList<String> answer = new ArrsyList<>();
        for(int i=0; i<record.length; i++){
            words = record[i].split("\\s");
            if(words[0].equals("Enter")){
                answer.add(String.format(FORMAT_ENTER, nickname.get(words[1])));
            }else if(words[0].equals("Leave")){
                answer.add(String.format(FORMAT_LEAVE, nickname.get(words[1])));
            }
        }

        return answer.toArray(new String[answer.size()]);
    }
}

java String에서는 format함수를 제공합니다.

문자열의 형식을 저장하고 입력값을 형식에 적용한 문자열을 리턴함으로서 메시지의 형식이 변경되어도 미리 선언해둔 출력 형식만 변경하면 쉽게 이를 적용할 수 있습니다.

결과 메시지들을 담을 자료구조에 있어서도 Vector를 상속받는 Stack보다 ArrayList가 더 효율적이라고 판단하여 자료구조를 변경하였습니다.

Vector vs ArrayList

Vector와 ArrayList는 모두 AbstrackList를 상속받아 구현된 클래스입니다.

배열로 구현되어 있어 인덱스를 이용한 빠른 값 찾기가 가능하고 자동으로 메모리 공간을 늘려주는 작업을 수행합니다.(Vector는 크기를 2배, ArrayList는 1.5배로 증가)

그러나 Vector와 ArrayList는 동기화에 있어 큰 차이를 가지고 있습니다.

Vector는 동기화가 되어 있으나 ArrayList는 동기화가 되어있지 않습니다.

Vector는 한번에 하나의 스레드만 접근할 수 있고 ArrayList를 그렇지 않기 때문에 단일 스레드 작업에 대해서 ArrayList가 조금 더 빠른 속도를 보인다고 할 수 있겠습니다.