ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [CodeKata] 프로그래머스 : 8.15(일), 광고 삽입
    Algorithm 2021. 8. 15. 16:45
    반응형

    🥋 Oooth More!! (Level 3) 

     

    🧮 풀이

    * 실패한 풀이이다. 극소 케이스는 맞았으나, 대부분 실패나 시간초과가 발생했음.

    function toSec(time) {
      time = time.split(":");
      return Number(time[0] * 3600 + time[1] * 60 + time[2]); 
    }
    
    function solution(play_time, adv_time, logs) {
      function getPlays(start, end, logs) {
        let play = 0;
        logSecs.forEach((log) => {
          if (log[1] < start || log[0] > end) return;
            play += (Math.min(log[1], end) - Math.max(log[0], start));
          })
        return play;
      }
        
      const playtime = toSec(play_time);
      const advtime = toSec(adv_time);
      const logSecs = logs.map((log, i) => [...log.split("-").map(time => toSec(time)), i]).sort((a,b) => a[0]-b[0])
      let totalPlays = getPlays(0, advtime);
      let answer = -1;
      
      logSecs.forEach(([s,e,i]) => {
        const nowPlays = getPlays(s, Math.min(playtime, s+advtime));
        if (nowPlays > totalPlays) {
          totalPlays = nowPlays
          answer = i
        }
      })
      
      return answer === -1 ? "00:00:00" : logs[answer].substr(0,8);
    }

    0초와, 각 재생기록들의 시작시간마다 공익광고가 시작된다고 가정한 뒤, 각 경우의 총 재생시간(getPlays)을 비교하여 이를 최신화했다.

    'HH:mm:ss' 포멧을 초로 계산(toSec)한 뒤, 시간 차이값들의 합이 가장 큰 값으로 누적하여 이 시작시간을 최종적으로 반환했다.

     

    🖇 리뷰

    function solution (play_time, adv_time, logs) {
      const pt = calculateTime(play_time);
      const at = calculateTime(adv_time);
      const times = new Array(pt).fill(0);
      
      logs.forEach(log => {
        const [start, end] = log.split('-');
        const ws = calculateTime(start);
        const we = calculateTime(end);
        times[ws]++;
        times[we]--;
      });
       
      // 시청자수
      for(let i = 1; i <= pt; i++)
        times[i] += times[i-1];
      // 시청시간
      for(let i = 1; i <= pt; i++)
        times[i] += times[i-1];
      
      let sum = times[at-1];
      let idx = 0;
      
      for(let i = at-1; i < pt; i++) {
        if(sum < times[i] - times[i-at]) {
          sum = times[i] - times[i-at];
          idx = i - at + 1;
        }
      }
      
      return formatterTime(idx);
                   
    }
    
    const calculateTime = (time) => {
      const HHMMSS = time.split(':');
      const amount = HHMMSS[0]*3600 + HHMMSS[1]*60 + HHMMSS[2]*1;
      return amount;
    }
    
    const formatterTime = (time) => {
      let HH = time / 3600 >> 0;
      let MM = (time / 60 >> 0) % 60;
      let SS = time % 60;
      
      HH = HH > 9 ? HH : '0' + HH;
      MM = MM > 9 ? MM : '0' + MM;
      SS = SS > 9 ? SS : '0' + SS;
      
      return `${HH}:${MM}:${SS}`
    }

    * 출처https://velog.io/@longroadhome/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-LV.3-%EA%B4%91%EA%B3%A0-%EC%82%BD%EC%9E%85-JS

    1. calculateTime() 은 시간문구를 초값으로, formatterTime은 초값을 시간문구로 변환해주는 상반되는 메서드들이다.
    2. play_time, adv_time, logs의 [start, end] 변환에 calculateTime()이 사용된다. times는 pt만큼 1초단위로 만든 배열이다.
    3. logs를 순회하며, 각 log가 시작되는 시간의 times엔 1을 더하고, 끝나는 times엔 1을 뺀다.
    4. times를 순회하며, times[i]에 times[i-1]을 더해준다. 이러면 모든 초에서, 시청하고있는 사람수로 계산되는 것이다.
    5. for문이 한번 더 돈다. 이렇게 되면, 사람수들이 뒤로 계속 누적되므로 해당 시간까지의 누적 재생횟수가 되는 것이다.
    6. 가장 먼저, 영상을 0초(idx)에서 틀었다고 가정하면, 누적 재생횟수는 at만큼 지난 times[at-1] 값이 해당될 것이다.
    7. 그런 다음, at-1부터 pt까지 times를 순회한다. times[i] - times[i-at]가 해당 광고재생동안 누적 재생횟수가 된다. 이 값이, 현재 sum보다 큰 경우 최대값을 최신화하고, idx는 시작값인 i - at + 1로 최신화하면 된다.
    8. idx값이 우리가 찾는 정답이자 시작시간이다. 이를, formatterTime()을 통해 시간문구로 변환하여 반환하면 된다.

     

    LV3이라 어렵기도 하고 예전에 비해 시간투자를 많이 못하고 있긴 하나, 이번 문제도 고도의 알고리즘을 사용하는 문제는 아니었다.

    문제를 풀 수 있는 방법과 다양한 시도를 좀 더 적용해본 뒤에, 모범답안을 학습할 수 있도록 알고리즘에 일정시간을 할당해버릇 해야겠다.

    반응형
Designed by Tistory.