본문 바로가기
일반 학습/코딩 테스트

[프로그래머스] 방금그곡

by StelthPark 2022. 3. 9.

처리조건

풀이

입력값 : solution("ABCDEFG", ["12:00,12:14,HELLO,CDEFGAB", "13:00,13:05,WORLD,ABCDEF"]);

우선 musicinfos를 받아 map를 활용해 각 요소마다 elString으로 split(",")를 사용해 , 를 기준으로 나누어 주었다.

입력값을 기준으로 아래처럼 나누어진다.

여기서 우리는 시간이 12:00~ 12:14 처럼 뒤에 시간의 분에서 앞에 시간의 분을 빼면 총 분을 구하는게 쉽지만 만약에 12:30~13:20 이렇게 된다면 단순히 분만 빼주는 것으론 총 분을 구할 수 없다. 그래서 뒤 시간의 시간이 앞 시간의 시간보다 크다면 60에서 앞시간의 분을 빼주고 거기에 뒷 시간의 분을 더하는 식으로 계산하도록 하였다. slice를 사용했고 allcount로 총 가동 분을 받게 된다. 

 

이후에 allcount에 따라 인덱스3에 위치한 알파벳들을 만들어줄 것이다. allcount보다 해당하는 알파벳길이가 크거나 같으면 alllcount를 뺀 만큼을 현 알파벳길이에서 pop할것이고 다시 인덱스3에 할당한다. 그 밖에는 allcount에서 인덱스3의 길이를 나눠떨어지면 길이만큼 현알파벳을 repeat하여 더하고 나머지가 남으면 나머지만큼 한번 더 더한다. 그리고 이후에 인덱스1에 위치한 음악이름, 총 분 , 만들어진 알파벳을 배열에 담아 리턴한다.

 

지금까지 작성한 코드는 아래와 같다.

function solution(m, musicinfos) {
  const arr = musicinfos.map((elString) => {
    let splitEl = elString.split(",");
    console.log(splitEl);
    let allcount = 0;
    if (Number(splitEl[0].slice(0, 2)) < Number(splitEl[1].slice(0, 2))) {
      allcount = 60 - Number(splitEl[0].slice(3)) + Number(splitEl[1].slice(3));
    } else {
      allcount = Number(splitEl[1].slice(3)) + Number(splitEl[0].slice(3));
    }

    if (allcount <= splitEl[3].length) {
      let deleteCnt = splitEl[3].length - allcount;
      for (let i = 0; i < deleteCnt; i++) {
        let temp = splitEl[3].split("");
        temp.pop();
        temp = temp.join("");
        splitEl[3] = temp;
      }
    } else {
      let desiCnt = Math.floor(allcount / splitEl[3].length);
      let plusString = splitEl[3];
      if (allcount % splitEl[3].length === 0) {
        for (let i = 0; i < desiCnt - 1; i++) {
          splitEl[3] += plusString;
        }
      } else if (allcount % splitEl[3].length !== 0) {
        for (let i = 0; i < desiCnt - 1; i++) {
          splitEl[3] += plusString;
        }
        splitEl[3] += plusString.slice(0, allcount % plusString.length).join("");
      }
    }

    return [splitEl[2], allcount, splitEl[3]];
  });
  console.log(arr);
  }

 

여기서 문제가 발생했다. 앞전에 인덱스3에 위치한 알파벳들이 #이들어가는 경우 하나로 묶어 하나의 분으로 계산해야한다는것이다. 예를 들어 ABCDE가 있다면 그냥 5개로 볼수 있지만 A#BCDE이렇게 돼있다면 A#은 한 음악기호로 본다.

그러면 총 분도 달라질 것이고 결과도 달라질 것이다. 

  const arr = musicinfos.map((mi) => {
    const [start, end, title, code] = mi.split(",");
    const hour = end.slice(0, 2) - start.slice(0, 2);
    const minute = end.slice(3) - start.slice(3);
    const runtime = 60 * hour + minute;

    const codeArr = code.match(/[A-Z]#?/g);
    let stream = code.repeat(Math.floor(runtime / codeArr.length));
    stream += codeArr.slice(0,runtime % codeArr.length).join("");
    return [title, runtime, stream];
  });

 

로직을 바꾸었다. 효율적이고 가독성을 높이기 위해 검색을 해보았고 제일 깔끔하였다. 3번인덱스로 오는 code를 match를 통해 #이 붙은것을 예외 처리하여 codeArr로 인덱스를 가진 배열형태를 만들어준다.

 

이후 인자로 받은 m이랑 일치하는게 있는지 검색하게 되는데 arr을 찍어보면 아래와 같다.

m과 일치하는지 검색하고 가장 긴 분의 음악이름을 리턴하는 코드이다.

const answer = arr.filter(([_, __, stream]) => {
    let i = stream.indexOf(m);
    if (i === -1) return false;
    while (i !== -1) {
      if (stream[i + m.length] !== "#") return true;
      i = stream.indexOf(m, i + 1);
    }
  });
  if (!answer.length) return "(None)";

  answer.sort((a, b) => {
    if (a[1] === b[1]) return 0;
    return b[1] - a[1];
  });
  return answer[0][0];

stream으로 각 arr의 요소마다 알파벳이 들어오게 될 것이다. indexOf로 m을 검색하여 위치한 인덱스 번호를 받고 #과 관계없이 아예 없다면 false를 리턴하여 최종적인 answer에 담지않게된다. 그외에 while문 돌려 i가 -1이 아닐때 까지만 돌리게 된다. stream의 인덱스 번호로 현재 m의 위치에 m의 길이만큼더하면 m을 찾은 다음 m의 다음번째가 된다. 이것이 #이 아닐시 맞아떨어진것이니 true를 리턴해 answer에 담는다. 만약 #이라면 m을 찾기시작한 인덱스를 1올려서 다시 m을 찾는다 못찾을시 i는 -1이 되고 또 i+1를 하여 검색되는 m이 있다면 다시 뒤에 #이있는지 확인.. 반복 결국엔 indexOf가 -1이 나와 없으면 최종적으로 false 가 리턴된다.

 

아래에서 찾은 answer이 하나도없다면 조건에 맞는게 없다는 것으로 처리하고

있다면 sort하여 각 요소의 1번인덱스인 총 분을 계산하여 높은순으로 맨앞으로 옮긴다. 그리고 해당하는 맨 앞 이름을 리턴한다.

'일반 학습 > 코딩 테스트' 카테고리의 다른 글

[프로그래머스] 파일명 정렬  (0) 2022.03.11
[프로그래머스] 압축  (0) 2022.03.10
[프로그래머스] 캐시  (0) 2022.03.09
[프로그래머스] 프렌드 4블록  (0) 2022.03.09
[프로그래머스] 순위 검색  (0) 2022.03.08

댓글