카카오 코딩테스트 | 방금그곡

문제 바로가기

오늘 하루종일 붙잡고 있었던 문제.. 풀어내긴 했지만 진이 다 빠져서 설명 포기^^!

삽질

재생 시간을 잘못 구했다.

13:30 - 14:40 처럼 끝난 시각의 분이 시작 시각의 분보다 큰 경우만 생각했다. 13:50 - 14:00 처럼 끝난 시각의 분이 더 작은 경우도 고려해야 한다.


나름 노력한 점

주어진 input을 의미 있는 자료구조로 만들기 위해 Map을 사용했다. 값을 한번에 뽑아오는 게 편해서 Map을 썼는데 이 문제에서는 딱히 그런 작업을 할 일이 없어서 그냥 객체로 사용했어도 됐을 것 같다. 근데 아직 미숙해서 코드가 너무 지저분하다. 자료구조 만들 때도 함수를 만들어서 썼어야 했는데 하다가 너무 짱나서 그냥 막 써버렸다. 😅


배운 점

이렇게 input을 받아 사용 가능한 데이터로 처리하는 걸 tokenize 라고 하는 걸 직접 느꼈다. 코코아 수업 때 들었던 개념인데 직접 해보니까 뜻이 와닿았다. 여기서 중요한 점이 있었는데, 각각의 token을 비교가 가능하도록 만들어줘야한다. 무슨 뜻이냐면 문제에서 C와 같은 것은 한글자, C#와 같이 #이 붙은 것은 두글자이다. 이것을 ['C', 'C#'] 이렇게 배열로 만들던지, 아니면 #이 붙은 건 문제에서 안쓰이는 아예 다른 문자(예를 들면 소문자. 'Cc')로 치환하는 등 적절한 처리가 필요하다.


설계


코드

function solution(m, musicinfos) {
  const getPlayTime = (start, end) => { // string type의 시간을 받아 재생 시간 리턴
    const startTime = start.split(':').map(str => Number(str));
    const endTime = end.split(':').map(str => Number(str));
    if(startTime[1] <= endTime[1]) {
      return (endTime[0] - startTime[0]) * 60 + endTime[1] - startTime[1];
    }
    if(startTime[1] > endTime[1]) {
      endTime[1] += 60;
      endTime[0] -= 1;
      return (endTime[0] - startTime[0]) * 60 + endTime[1] - startTime[1];
    }
  }

  const getUnitArr = (musicSheet) => {
    const splitMusicSheet = musicSheet.split('');
    for(let i = 1; i < splitMusicSheet.length; i++) {
      if(splitMusicSheet[i] === '#') {
        splitMusicSheet[i - 1] = splitMusicSheet[i - 1].toLowerCase();
      }
    }
    return splitMusicSheet.filter(scale => scale !== '#')
  }

  // string type의 악보 받아 한 곡이 몇 분인지 리턴
  const getMusicPlayTime = (musicSheet) => { 
    const unitArr = getUnitArr(musicSheet);
    const musicPlayTime = unitArr.length;
    return musicPlayTime
  }

  // 재생 시간에 맞게 노래 자르거나 이어붙이기 - 리턴값을 m과 비교할 것임
  const getEntireMusicSheet = (playTime, musicPlayTime, unitArr) => { 
    let entireMusicSheetArr = [];
    const repeat = Math.floor(playTime / musicPlayTime);
    const remain = playTime % musicPlayTime;
  
    if(playTime < musicPlayTime) {
      return unitArr.slice(0, playTime + 1).join('');
    }

    if(playTime >= musicPlayTime) {
      for(let i = 1; i <= repeat; i++) {
        entireMusicSheetArr.push(...unitArr);
      }
      entireMusicSheetArr.push(...unitArr.slice(0, remain));
    }
    return entireMusicSheetArr.join('');
  }

  const hasM = (entireMusicSheet, m) => {
    return (entireMusicSheet.includes(m) === true) ? true : false
  }

  // --------------------------------------- 실행부 ---------------------------------------

  const tokenizedM = getUnitArr(m).join('');
  const splitInfos = musicinfos.map(info => info.split(','));
  console.log(splitInfos)
  let data = [];
  for(let i = 0; i < splitInfos.length; i++) {
    const infoMap = new Map();
    const playTime = getPlayTime(splitInfos[i][0], splitInfos[i][1]);
    const musicPlayTime = getMusicPlayTime(splitInfos[i][3]);
    const unitArr = getUnitArr(splitInfos[i][3]);
    const entireMusicSheet = getEntireMusicSheet(playTime, musicPlayTime, unitArr)

    infoMap.set('순서', i);
    infoMap.set('제목', splitInfos[i][2]);
    infoMap.set('재생된시간', playTime);
    infoMap.set('재생된전체악보', entireMusicSheet);
    infoMap.set('m포함?', hasM(entireMusicSheet, tokenizedM));
    data.push(infoMap);
  }

  const musicsContainM = data.filter(musicInfo => musicInfo.get('m포함?') === true)
  
  if(musicsContainM.length === 0) return '(None)';
  if(musicsContainM.length === 1) return musicsContainM[0].get('제목');
  
  let comparedItem = musicsContainM[0]
  for(let i = 1; i < musicsContainM.length; i++) {
    const currItem = musicsContainM[i]
    if(comparedItem.get('재생된시간') < currItem.get('재생된시간')) {comparedItem = currItem}
    if(comparedItem.get('재생된시간') >= currItem.get('재생된시간')) continue;
  }
  return comparedItem.get('제목');
}

좋은 웹페이지 즐겨찾기