프로그래머스-2018 KAKAO BLIND RECRUITMENT ( 방금그곡 by Java )

Flash·2022년 2월 21일
0

Programmers-Algorithm

목록 보기
40/52
post-thumbnail

구현 ( 문자열 파싱 )

프로그래머스 2018 KAKAO BLIND RECRUITMENT Level 2 문제 방금그곡Java를 이용해 풀어보았다. 생각보다 오래 걸렸고.. 특정 테스트 케이스를 계속 통과하지 못해서 머리가 좀 아팠다. 테스트 케이스 25,26,28을 계속 통과하지 못했다. 어떤 이유에선지는 후술하겠다.

내가 푼 풀이는 정말 간단한 로직을 너무나도 길고 복잡하게 구현해놔서 올리기도 부끄럽지만.. 더 좋은 코드를 보며 성장하면 되지!

문제 링크 첨부한다.
https://programmers.co.kr/learn/courses/30/lessons/17683


악보 수정

C#CB가 기본 악보이고 들은 멜로디 문자열 mCBC일 경우를 생각해보자. 6분 동안 재생됐다면 C#CBC#CB가 재생됐을 것이다. 그러면 CBC를 포함하고 있는지 확인하게 되면 있다고 판단한다. 하지만 실제 재생된 멜로디는 CBC가 아닌 CBC#이 재생된 것이다. 따라서 잘못된 로직으로 처리된다.

이를 해결하기 위해 #이 붙은 음들을 모두 다른 문자로 치환해줘야 한다. 예를 들어 C#c로, D#d로 치환해주면 기본 악보가 cCB가 될 것이다. 그러면 6분동안 재생된 악보는 cCBcCB가 될 것이고 주어진 멜로디 CBC를 포함하지 않기 때문에 정상적으로 처리된다.

이러한 입력값이 주어질 경우 제대로 처리하지 못해 테스트 케이스 25,26,28이 계속 실패가 떴던 것이다.

이를 위해 다음과 같은 메소드를 선언했다.

static String transformMusic(String org){
   org = org.replaceAll("C#", "c");
   org = org.replaceAll("D#", "d");
   org = org.replaceAll("E#", "e");
   org = org.replaceAll("F#", "f");
   org = org.replaceAll("G#", "g");
   org = org.replaceAll("A#", "a");
   return org;
}

재생된 시간만큼 악보 재구성

기본 악보가 주어지면 재생되 시간만큼의 악보로 다시 만들어줘야 한다. 이를 위해 재생시간기본 악보를 param으로 넘겨줘서 실제 재생된 악보를 반환하면 된다.

이를 위해 다음과 같은 메소드를 선언했다.

static String createPlayedSheet(int playTime, String basicSheet){
        basicSheet = transformMusic(basicSheet);

        String res = "";
        int idx = 0;
        while(playTime--!=0){
            res += ""+basicSheet.charAt(idx);
            idx++;
            if(idx==basicSheet.length())   idx = 0;
        }

        return res;
    }

재생된 곡에 대한 클래스 선언

재생된 곡들은 다음과 같은 정보를 갖고있다.

  1. 재생된 순번
  2. 제목
  3. 재생 시간
  4. 실제 재생된 악보

위의 정보들을 갖춘 하나의 클래스를 선언해서 좀 더 보기 쉽게 작성했다. 코드는 아래와 같다.

static class Info{
        int idx;
        String title;
        int playTime;
        String playedSheet;

        Info(int idx, String title, int playTime, String basicSheet){
            this.idx = idx;
            this.title = title;
            this.playTime = playTime;
            this.playedSheet = createPlayedSheet(playTime, basicSheet);
        }

        Integer getPlayTime(){ return this.playTime; }
        Integer getIdx(){ return this.idx; }
    }

앞서 봤던 createPlayedSheet 메소드를 여기서 생성자 코드 가운데 사용한 것을 확인할 수 있다.
그럼 주어진 musicinfos 배열을 돌며 재생된 하나의 곡에 대해 Info 객체를 생성해주며 List에 추가해주면 된다.

코드는 아래와 같다.

ArrayList<Info> list = new ArrayList<>();

int idx = 1;
for(String info: musicinfos){
       String[] split = info.split(",");
       Time begin = new Time(split[0]);
       Time end = new Time(split[1]);
       String title = split[2];
       String basicSheet = split[3];
       list.add(new Info(idx++, title, begin.getDiff(end), basicSheet));
}

네오의 멜로디를 포함한 Info 객체 걸러내기

그럼 이제 모든 재생된 곡들에 대한 Info 객체를 완성했기 때문에 실제로 네오가 들었던 멜로디가 포함된 객체들만 남겨두면 된다. 이 때는 Iterator를 사용해서 해당 멜로디를 포함하지 않은 객체들은 날려버렸다.

Iterator<Info> itr = list.iterator();
while(itr.hasNext()){
     Info cur = itr.next();
     if(!cur.playedSheet.contains(m))    itr.remove();
}
if(list.size()==0)  return "(None)";

만약 단 하나의 재생된 곡도 해당 멜로디를 포함하지 못했다면 List가 비었을테고 그럼 size를 확인해서 0일 경우에는 문제 조건대로 None을 반환했다.

하지만 아직 해야할 작업이 남았다. 조건을 만족하는 여러 곡이 있다면 그 중 재생시간이 가장 긴 녀석들을 반환해야 하며, 재생시간이 같은 놈들이 있다면 그 중에서도 순번이 빠른 녀석들을 반환해줘야 한다.

이를 위해서는 Comparator를 사용해서 sort해줬다.
Info 클래스에서 재생시간순번을 반환하는 getter 메소드를 미리 선언해놔서 다음과 같이 정렬했다.

list.sort(Comparator.comparing(Info::getPlayTime).reversed().
					thenComparing(Info::getIdx));

이렇게 정렬까지 마쳤으면 가장 앞에 있는 녀석의 타이틀을 반환해주면 된다.

String answer = list.get(0).title;
return answer;

다른 사람들의 풀이를 보면 훨씬 간단하고 압축적인 코드를 작성해놨다. 그런데 나는 사실 시험 시간에 시간 압박에 쫓기며 그렇게까지 응축되고 멋진 코드를 짜진 못할 것 같다. 그래서 나는 항상 객체지향적으로 코드를 짜서 구조화시키려 한다. 눈에 딱 보이는 구조로 짜지 않으면 나는 생각이 다 mix된다. 그래서 항상 필요한 정보들 중 서로 관련된 녀석들에 대해 클래스를 정의해서 다루려고 한다.

꼭 짧고 더 멋있고 간결한 코드로 짜는 것만이 코딩 테스트에서 능사는 아닌 것 같다.. 머리가 안 되는 나같은 놈들한테는...ㅋㅋㅋ

profile
개발 빼고 다 하는 개발자

0개의 댓글