연습장/프로그래머스 문제풀이

[프로그래머스 Level 2] 방금그곡 - JavaScript

Tesseractjh 2022. 6. 10. 22:52

🔗 문제 링크

https://programmers.co.kr/learn/courses/30/lessons/17683

 

코딩테스트 연습 - [3차] 방금그곡

방금그곡 라디오를 자주 듣는 네오는 라디오에서 방금 나왔던 음악이 무슨 음악인지 궁금해질 때가 많다. 그럴 때 네오는 다음 포털의 '방금그곡' 서비스를 이용하곤 한다. 방금그곡에서는 TV,

programmers.co.kr

✏️ 풀이

function solution(m, musicinfos) {
    const normalize = (melody) => {
        return melody.replace(/([A-Z])#/g, (_, group) => group.toLowerCase());
    };
    
    const getMin = (time) => {
        const [hour, minute] = time.split(':').map(Number);
        return hour * 60 + minute;
    };
    
    const getDiff = (start, end) => {
        return getMin(end) - getMin(start);
    };
    
    const music = musicinfos.map(info => {
        const [start, end, title, melody] = info.split(',');
        return {
            time: getDiff(start, end),
            title,
            melody: normalize(melody)
        };
    });
    
    const targetMelody = normalize(m);
    let output = { title: '(None)' };
    music.forEach(info => {
        const { time, title, melody } = info;
        let compMelody = melody.repeat(2);
        let count = 2;
        while (targetMelody.length + melody.length - 1 > compMelody.length) {
            compMelody += melody;
            count++;
        }
        const index = compMelody.indexOf(targetMelody);
        if (index >= 0 && index + targetMelody.length <= time) {
            if (output.title === '(None)' || output.time < time) {
                output = info;
            }
        }
    });
    return output.title;
}

musicinfos를 순회하면서 각 음악에 대한 정보를 갖고 { time, title, melody } 객체로 변환하여 music에 배열의 형태로 저장한다. 이 때, time은 음악이 재생된 시간의 양으로 바꾸고, melody는 C#, D#, F#, G#, A# 같이 두 글자로 된 음을 c, d, f, g, a로 모두 한 글자로 바꿔준다. (normalize)

 

마찬가지로 찾고자 하는 멜로디인 m도 normalize 함수로 모든 음을 한 글자로 변환한다.

 

output의 초기값을 제목이 (None)인 음악의 정보로 설정한다. 그리고 나서 music을 순회한다.

targetMelody와 현재 순회중인 음악의 melody를 비교할 때, 최소한 (targetMelody의 길이 + melody의 길이 - 1)만큼 melody를 반복 재생해야 모든 경우의 수를 다 확인할 수 있다. 예를 들어 targetMelody가 ABCAB 이고, melody가 BCA라면, melody를 BCA|BCA|B 까지는 재생해야 가능한 모든 5자리 멜로디를 확인할 수 있다. 따라서 compMelody에 계속 melody를 반복해서 최소한 모든 경우를 다 탐색할 수 있는 길이까지 만들어야 한다.

 

이렇게 반복재생한 melody를 이어붙여 만든 compMelody에서 targetMelody의 위치를 찾는다. 위 단계에서 아무런 제한 없이 melody를 이어붙였지만, 음악은 각각의 재생 시간이 있고, 이 재생 시간을 넘어서는 길이만큼의 melody는 재생되지 않는다. 따라서, 지금 찾은 targetMelody가 실제로 재생이 가능한 시간대에 있었는지를 확인해야 한다.

 

일단 compMelody에 targetMelody가 없으면 -1을 반환하므로, index >= 0이어야 한다. 그리고 index에 targetMelody의 길이를 더한 만큼이 time(음악이 재생된 분 수) 이하라면 실제로 재생이 되었던 것이다. 만약 실제로 재생이 되었다면 현재 output을 확인하여 title이 (None)이거나, 재생시간이 현재 time보다 더 짧다면 output을 현재 info로 교체한다.

 

순회가 끝난 뒤에 output의 title을 반환하였다.