
안녕하세요. 오늘은 프로그래머스의 방금그곡 문제를 풀어보겠습니다. 이 문제는 2018 KAKAO BLIND RECRUITMENT에 출제되었습니다.
https://programmers.co.kr/learn/courses/30/lessons/17683
문제 구현에 있어 C와 C#처럼 #이 붙은 음을 구분하는 것이 가장 까다로웠습니다. for문을 돌 때 다음 index의 string이 "#"이면 해당 index의 문자를 소문자로 치환하여 저장하는 방식으로 이를 해결하였습니다.
LinkedHashMap을 사용하여 순서를 저장하였습니다. LinkedHashMap의 key는 음표이고, value에는 제목을 저장하였습니다.
import java.text.*;
import java.util.*;
class Solution {
   public String solution(String m, String[] musicinfos) throws ParseException {
        String answer = "";
        //key: 음표, value: 제목
        LinkedHashMap<String, String> map = new LinkedHashMap<>();
        SimpleDateFormat dateFormat = new SimpleDateFormat("mm:ss");
        for (String str : musicinfos) {
            //music[0] = 시작시간, music[1] = 끝시간
            //music[2] = 제목, music[3] = 음표
            String[] music = str.split(",");
            Date start = dateFormat.parse(music[0]);
            Date end = dateFormat.parse(music[1]);
            int diff = (int) (end.getTime() - start.getTime()) / 1000;
            StringBuilder sb = new StringBuilder();
            int idx = 0;
            String[] lyrics = music[3].split("");
            for (int t = 0; t < diff; t++) {
            	//lyrics배열을 모두 돌면 배열의 처음으로 다시 이동
                if(idx == lyrics.length) idx = 0;
                if(idx < lyrics.length - 1) {
              	    //다음 문자가 #이면 소문자로 저장
                    if("#".equals(lyrics[idx+1])) {
                        sb.append(lyrics[idx].toLowerCase());
                        sb.append(lyrics[idx+1]);
                        idx++;
                    } else {
                        sb.append(lyrics[idx]);
                    }
                } else {
                    sb.append(lyrics[idx]);
                }
                idx++;
            }
            map.put(sb.toString(), music[2]);
        }
	//주어진 m도 #이 붙은 경우 소문자로 치환하여야 한다
        StringBuilder makeM = new StringBuilder();
        for (int i = 0; i < m.length(); i++) {
            if(i < m.length()-1) {
                if('#' == m.charAt(i+1)) {
                    makeM.append((char) (m.charAt(i)+32));
                } else {
                    makeM.append(m.charAt(i));
                }
            } else {
                makeM.append(m.charAt(i));
            }
        }
        m = makeM.toString();
        ArrayList<String> keyList = new ArrayList<>(map.keySet());
        int idx = 0;
        for(int i = 0; i < keyList.size(); i++) {
            String key = keyList.get(i);
            if(key.contains(m)) {
                if("".equals(answer)) {
                    answer = map.get(key);
                    idx = i;
                } else {
                    int pastLyricsLen = keyList.get(idx).length();
                    int nowLyricsLen = key.length();
                    if(nowLyricsLen > pastLyricsLen) {
                        answer = map.get(key);
                        idx = i;
                    }
                }
            }
        }
        if("".equals(answer)) answer = "(None)";
        return answer;
    }
}
처음엔 LinkedHashMap이 아닌 그냥 HashMap으로 문제를 풀었었다. 그랬더니 28번 테스트케이스에서 자꾸 실패가 떨어졌다. 이유는 HashMap에 있었다.
HashMap은 순서를 저장하지 않는다. 순서를 저장하기 위해서는 LinkedHashMap을 사용해야 한다.
문제에서 주어진 제약사항 중 "재생된 시간의 길이가 같으면 먼저 나온 곡이 answer다" 를 지키기 위해서는 순서를 저장해야 한다.
LinkedHashMap을 사용하니 문제없이 다 맞았다.😆
😆