코딩/Javascript

Javascript Algorithm - 방금그곡

AMD만세 2022. 3. 8. 10:54

 

1. 프로그래머스 - '방금그곡'

 

1) 문제

네오는 자신이 기억한 멜로디를 가지고 방금그곡을 이용해 음악을 찾는다. 그런데 라디오 방송에서는 한 음악을 반복해서 재생할 때도 있어서 네오가 기억하고 있는 멜로디는 음악 끝부분과 처음 부분이 이어서 재생된 멜로디일 수도 있다. 반대로, 한 음악을 중간에 끊을 경우 원본 음악에는 네오가 기억한 멜로디가 들어있다 해도 그 곡이 네오가 들은 곡이 아닐 수도 있다. 그렇기 때문에 네오는 기억한 멜로디를 재생 시간과 제공된 악보를 직접 보면서 비교하려고 한다. 다음과 같은 가정을 할 때 네오가 찾으려는 음악의 제목을 구하여라.

  • 방금그곡 서비스에서는 음악 제목, 재생이 시작되고 끝난 시각, 악보를 제공한다.
  • 네오가 기억한 멜로디와 악보에 사용되는 음은 C, C#, D, D#, E, F, F#, G, G#, A, A#, B 12개이다.
  • 각 음은 1분에 1개씩 재생된다. 음악은 반드시 처음부터 재생되며 음악 길이보다 재생된 시간이 길 때는 음악이 끊김 없이 처음부터 반복해서 재생된다. 음악 길이보다 재생된 시간이 짧을 때는 처음부터 재생 시간만큼만 재생된다.
  • 음악이 00:00를 넘겨서까지 재생되는 일은 없다.
  • 조건이 일치하는 음악이 여러 개일 때에는 라디오에서 재생된 시간이 제일 긴 음악 제목을 반환한다. 재생된 시간도 같을 경우 먼저 입력된 음악 제목을 반환한다.
  • 조건이 일치하는 음악이 없을 때에는 “(None)”을 반환한다.

 

2) 입력형식

입력으로 네오가 기억한 멜로디를 담은 문자열 m과 방송된 곡의 정보를 담고 있는 배열 musicinfos가 주어진다.

  • m은 음 1개 이상 1439개 이하로 구성되어 있다.
  • musicinfos는 100개 이하의 곡 정보를 담고 있는 배열로, 각각의 곡 정보는 음악이 시작한 시각, 끝난 시각, 음악 제목, 악보 정보가 ','로 구분된 문자열이다.
    • 음악의 시작 시각과 끝난 시각은 24시간 HH:MM 형식이다.
    • 음악 제목은 ',' 이외의 출력 가능한 문자로 표현된 길이 1 이상 64 이하의 문자열이다.
    • 악보 정보는 음 1개 이상 1439개 이하로 구성되어 있다.

 

3) 입출력 예

 

m musicinfos answer
"ABCDEFG" ["12:00,12:14,HELLO,CDEFGAB", "13:00,13:05,WORLD,ABCDEF"] "HELLO"
"CC#BCC#BCC#BCC#B" ["03:00,03:30,FOO,CC#B", "04:00,04:08,BAR,CC#BCC#BCC#B"] "FOO"
"ABC" ["12:00,12:14,HELLO,C#DEFGAB", "13:00,13:05,WORLD,ABCDEF"] "WORLD"

 

 

4) 내가 짠 코드

x. 주석달면서 공부 필요.

 

5) 다른사람 코드

 
function solution(m, musicinfos) {
    const arr = musicinfos.map((mi)=>{ // 입력 배열의 문자열 각각에 대해 수행한다.
        const [start, end, title, code] = mi.split(","); // 문자열에서 ,를 구분자로 각 정보를 분리
        const hour = end.slice(0,2)-start.slice(0,2); // 문자열의 0~1번째 문자는 시간
        const minute = end.slice(3)-start.slice(3); // 문자열의 3~4번째 문자는 분
        const runtime = 60 * hour + minute; // 총 재생 시간

        const codeArr = code.match(/[A-Z]#?/g); // 알파벳, 알파벳#를 찾아 각각 배열의 인덱스에 분리한다.
        let stream = code.repeat(Math.floor(runtime/codeArr.length)); // 곡이 반복된 수 n만큼 악보 정보를 더한다.
        stream += codeArr.slice(0,runtime % codeArr.length).join(""); // 재생 도중에 멈춘 시점의 음까지를 추가로 더해준다.
        return [title, runtime, stream]; // 음악 제목, 총 재생 시간, 재생된 음 정보를 반환한다.
    })

    // 다음의 filter 함수는 조건을 충족하는(return true하는) 원소만 출력하는 함수
    const answer = arr.filter(([_,__,stream])=>{ // 각각의 결과 배열에 대해 다음을 수행한다.
        let i = stream.indexOf(m); // 재생된 음 정보에 문자열 m이 포함되었는지 검사한다.
        if(i === -1) return false; // 포함되어있지 않다면 넘어간다.
        while(i !== -1){ // 포함되어 있다면
            if(stream[i+m.length] !== "#") return true;
            i = stream.indexOf(m, i+1);
           // 찾은 문자 뒤에 #이 없다면 배열 정보를 그대로 반환한다.
           // ( stream = ABC#EFG 일 때 m= ABC를 찾을 수 있다.) 
           // 찾은 문자 뒤에 #이 있다면 정답이 아니므로, 찾은 문자 뒤에 m과 일치하는 문자가 있는지 찾아야 한다.
        }        
    });
    if(!answer.length) return "(None)"; // answer 배열에 원소가 없다면 조건에 일치하는 음악이 없는 것.

    answer.sort((a,b)=>{
        if(a[1] === b[1]) return 0;
        return b[1] - a[1];
    }) // 1번 인덱스(총 재생수)가 같다면 순서를 유지하고, 같지 않다면 내림차순 정렬한다.
    return answer[0][0]; // 입력 순서 + 내림차순을 반영했으므로 배열의 첫번째 원소의 제목이 정답이다.
}