프로그래머스 방금그곡 JavaScript

2023년 5월 11일

프로그래머스 방금그곡

문제 풀이

방송된 곡들의 정보를 담은 musicinfos의 음악 중 멜로디 m이 포함된 음악을 찾는 문제다. 구현 문제라 생각이 들어 필요한 기능을 함수로 하나씩 구현했다.

함수

  • normalizationMelody(pitchs) : 악보나 멜로디의 음들을 배열로 정규화해서 반환하는 함수.
    매개변수 pitchs는 String 타입이다. pitchs를 문자 하나씩 조회할 때, 조회하는 문자가(temp) #인 경우 배열에 맨 뒤에 문자를 pop 하고 #을 더한다. 그 뒤엔 배열에 문자(temp)를 push 한다.
  • caculateMusicTime(start, end) : 음악의 시작 시각과 종료 시각을 받아 플레이 타임을 반환하는 함수.
    매개변수 start, end는 HH:MM 형식의 문자열이므로, split 한 후 계산을 위해 *=1을 통해 숫자 타입으로 변환시킨다.
    종료 시각의 분이 시작 시간의 분보다 작은 경우 종료 시각의 시간을 1 빼고 분에 60을 더한다. 이후 종료 시각의 시간 - 시작 시각의 시간, 종료 시각의 분 시작 시각의 분 계산을 하고, 계산된 시간에 * 60 + 분 을 반환한다.(분 형태의 시간)
  • getActualSoundPlay(sheetmusic, musicTime) : 음악의 악보와 플레이 시간을 입력받아 실제 재생되는 음들을 반환하는 함수.
    매개변수로 받은 악보 sheetmusicnormalizationMelody(pitchs)를 통해 배열로 정규화한 뒤, 정규화된 악보를 플레이 시간 동안 반복한다.
  • checkMusic(soundPlayed) : 재생되는 음들 중에 찾는 멜로디가 포함되는지 확인하는 함수, 찾을 경우 true, 못 찾을 경우 false를 반환.
    찾는 멜로디 m이 정규화된 배열 m_normalization 길이만큼 매개변수인 재생되는 음 soundPlayed를 slice 하여 비교

메인

매개변수 musicinfos를 하나씩 조회하면서 현재 음악의 플레이 시간, 제목, 실제 재생되는 음을(musicTime, musicTitle, musicSoundPlayed) 구하고 실제 재생되는 음을 통해 현재 음악이 찾는 멜로디가 포함되어 있으면 {제목, 실행 시간, musicinfos의 인덱스} 객체 형태로 answer에 push 한다. 이는 조건이 일치하는 음악이 여러 개일 수도 있기 때문이다.
모든 음악을 조회한 뒤,
answer의 길이가 0이면 조건이 일치하는 음악이 없는 경우로 "(None)"을 리턴
길이가 1이면 조건이 일치하는 음악이 하나이므로 그 음악의 제목을 리턴
길이가 2 이상일 경우 플레이 시간이 제일 긴 순서대로, 플레이 시간이 같은 경우 먼저 입력된 순서대로 정렬한다. 맨 앞에 음악이 해당 조건에 부합하는 음악이므로 이 음악의 제목을 리턴

solution.js
function solution(m, musicinfos) {
    const answer = [];
  
    const normalizationPitch = (pitchs) => {
        const arr = [];
        for (let i = 0; i < pitchs.length; i++) {
            const temp = pitchs[i] !== '#' ? pitchs[i] : arr.pop() + '#';
            arr.push(temp);
        }
        return [...arr];
    };
    
    const m_normalization = normalizationPitch(m);
    
    const caculateMusicTime = (start, end) => {
        let [startH, startM] = start.split(':');
        let [endH, endM] = end.split(':');
        
        startH *= 1;
        startM *= 1;
        endH *= 1;
        endM *= 1;
        
        if (endM < startM) {
            endM += 60;
            endH -= 1;
        }
        
        const timeH = endH - startH;
        const timeM = endM - startM;
        
        return timeH * 60 + timeM;
    };
    
    const getActualSoundPlay = (sheetmusic, musicTime) => {
        let idx = 0;
        const arr = [];
        const sheetmusic_normalization = normalizationPitch(sheetmusic);
        const musicLength = sheetmusic_normalization.length;
        
        for (let time = 0; time < musicTime; time++) {
            if (idx === musicLength) {
                idx = 0;
            }
            arr.push(sheetmusic_normalization[idx++]);
        } 
        return [...arr];
    };
    
    const checkMusic = (soundPlayed) => {
        const mValue = m_normalization.length;
        const maxValue = musicSeetMusic.length - mValue + 1;
        for (let i = 0; i < maxValue; i++) {
            const temp = musicSeetMusic.slice(i, i + mValue).join('');
    
            if (temp === m) {
                return true;
            }
        }
        return false;
    }
    
    musicinfos.forEach((item, idx) => {
        const musicinfo = item.split(',');

        const musicTime = caculateMusicTime(musicinfo[0], musicinfo[1]);
        const musicTitle = musicinfo[2];
        
        const musicSoundPlayed = getActualSoundPlay(musicinfo[3], musicTime);

        if (checkMusic(musicSoundPlayed)) {
            const passMusic = {
                title: musicTitle,
                runningTime: musicTime,
                index: idx
            };
            answer.push(passMusic);
        }
        
    });
    
    if (answer.length === 0) {
        return "(None)";
    }
    else if (answer.length === 1) {
        return answer[0].title;
    }
    else {
        answer.sort((a, b) => {
            if (a.runningTime > b.runningTime) {
                return -1;
            }
            if (a.runningTime < b.runningTime) {
                return 1;
            }
            if (a.index > b.index) {
                return 1;
            }
            if (a.index < b.index) {
                return -1;
            }
        });
        
        return answer[0].title;
    }
    
    return answer;
}

댓글