[코테 문제 풀기] 프로그래머스

given·2024년 10월 16일

TIL

목록 보기
4/8
post-thumbnail

📚 문제 설명

당신은 동영상 재생기를 만들고 있습니다. 당신의 동영상 재생기는 10초 전으로 이동, 10초 후로 이동, 오프닝 건너뛰기 3가지 기능을 지원합니다. 각 기능이 수행하는 작업은 다음과 같습니다.

  • 10초 전으로 이동: 사용자가 "prev" 명령을 입력할 경우 동영상의 재생 위치를 현재 위치에서 10초 전으로 이동합니다. 현재 위치가 10초 미만인 경우 영상의 처음 위치로 이동합니다. 영상의 처음 위치는 0분 0초입니다.
  • 10초 후로 이동: 사용자가 "next" 명령을 입력할 경우 동영상의 재생 위치를 현재 위치에서 10초 후로 이동합니다. 동영상의 남은 시간이 10초 미만일 경우 영상의 마지막 위치로 이동합니다. 영상의 마지막 위치는 동영상의 길이와 같습니다.
  • 오프닝 건너뛰기: 현재 재생 위치가 오프닝 구간(op_start ≤ 현재 재생 위치 ≤ op_end)인 경우 자동으로 오프닝이 끝나는 위치로 이동합니다.

동영상의 길이를 나타내는 문자열 video_len, 기능이 수행되기 직전의 재생위치를 나타내는 문자열 pos, 오프닝 시작 시각을 나타내는 문자열 op_start, 오프닝이 끝나는 시각을 나타내는 문자열 op_end, 사용자의 입력을 나타내는 1차원 문자열 배열 commands가 매개변수로 주어집니다. 이때 사용자의 입력이 모두 끝난 후 동영상의 위치를 "mm:ss" 형식으로 return 하도록 solution 함수를 완성해 주세요.

⚡️ 제한사항

  • video_len의 길이 = pos의 길이 = op_start의 길이 = op_end의 길이 = 5
    - video_len, pos, op_start, op_end"mm:ss" 형식으로 mmss초를 나타냅니다.
    - 0 ≤ mm ≤ 59
    - 0 ≤ ss ≤ 59
    - 분, 초가 한 자리일 경우 0을 붙여 두 자리로 나타냅니다.
    - 비디오의 현재 위치 혹은 오프닝이 끝나는 시각이 동영상의 범위 밖인 경우는 주어지지 않습니다.
    - 오프닝이 시작하는 시각은 항상 오프닝이 끝나는 시각보다 전입니다.
  • 1 ≤ commands의 길이 ≤ 100
    - commands의 원소는 "prev" 혹은 "next"입니다.
    - "prev"10초 전으로 이동하는 명령입니다.
    - "next"10초 후로 이동하는 명령입니다.

🔥 문제 풀이

어려운 문제는 아닌것 같다. 한번 풀어보자.
포인트는 3개

⭐️ 포인트

  1. prev,next 는 10초(sec) 간격으로 움직임을 명령한다.
  2. 변경 지점이 오프닝 구간(op_start ≤ 현재 재생 위치 ≤ op_end)인 경우 op_end로 설정
  3. 변경 지점이 0보다 작으면 0, video_len보다 크면 video_len과 같다.

문제풀이

인자값들은 commands를 제외하고 모두 string 타입이다.

function solution(video_len, pos, op_start, op_end, commands) {
  let answer = "";

  // string 타입의 time을 초(sec) number 타입으로 계산하여 절대값을 구한다.
  function getSecondTime(time) {
    const [mm, ss] = time.split(":").map((time) => parseInt(time, 10));
    return mm * 60 + ss;
  }

  // 각각의 절댓값(sec)
  const videoTime = getSecondTime(video_len);
  // pos 위치는 commands에 따라 변경되니 let으로 선언한다.
  let currentTime = getSecondTime(pos);
  const opStartTime = getSecondTime(op_start);
  const opEndTime = getSecondTime(op_end);

  // commands 명령어에 따라 변경될 값을 객체로 분리해둔다.
  const controlTime = {
    prev: -10,
    next: 10,
  };
  // commands를 for 문 돌려서 pos 위치를 변경해준다.
  for (let x of commands) {
    currentTime = currentTime + controlTime[x];
    // 오프닝 시간 점검 
    if (opStartTime <= currentTime && opEndTime >= currentTime)
      currentTime = opEndTime;
  }

  // video 길이에 맞는지 점검
  if (currentTime < 0) currentTime = 0;
  if (currentTime > videoTime) currentTime = videoTime;

  // 분(min),초(sec)를 구해준다.
  const min = Math.floor(currentTime / 60); //소수점 밑으로는 필요없으니 내림처리
  const sec = currentTime % 60;

  answer = `${String(min).padStart(2, "0")}:${String(sec).padStart(2, "0")}`;

  return answer;
}

좋았어. 가보자!

☠️ 오류1

안되넹...

오류1 원인 및 해결

아 이동값 뿐만 아니라 pos의 모든 위치가 오프닝 구간에 있으면 안되나 보다.
오프닝 시간 점검을 commend 확인 전에도 한번 넣고 다시 돌려보았다.

function solution(video_len, pos, op_start, op_end, commands) {
  let answer = "";
  ...
  // 추가!!
  if (opStartTime <= currentTime && opEndTime >= currentTime)
      currentTime = opEndTime;
  
  for (let x of commands) {
    currentTime = currentTime + controlTime[x];
    if (opStartTime <= currentTime && opEndTime >= currentTime)
      currentTime = opEndTime;
  }
  ...
  return answer;
}


됐다~! 제출 해보고 맞게 동작하는지 확인해보자.

☠️ 오류2

오류...⚡️
어렵네 이거... 누가 쉽다고 했어. 내가 했지 ㅁㅊㄴ

오류2 원인 및 해결

원인을 생각해보자. 오프닝 시간 검사를 pos의 시작부터 모든 변경값을 검사했는데 video_len 체크는 마지막에 한번 했던게 생각났다. 비디오 플레이어를 만들거면 당연히 모든 변경사항에 적용됐어야 했는데 수정해보자

function solution(video_len, pos, op_start, op_end, commands) {
  ...
  if (opStartTime <= currentTime && opEndTime >= currentTime)
      currentTime = opEndTime;
  if (currentTime < 0) currentTime = 0;
  if (currentTime > videoTime) currentTime = videoTime;
    
  for (let x of commands) {
    currentTime = currentTime + controlTime[x];
    if (opStartTime <= currentTime && opEndTime >= currentTime)
      currentTime = opEndTime;
    if (currentTime < 0) currentTime = 0;
    if (currentTime > videoTime) currentTime = videoTime;
  }
  ...
  return answer;
}

☠️ 오류3

어우 짜증나 또 하나 틀렸다.
검사 로직을 for문 안에 넣어주었다.

😂 정답

드디어..😂

맞혀도 맞힌 기분이 안든다. Lv.1에 이러면 안되는데 더 공부하자.

전체코드

function solution(video_len, pos, op_start, op_end, commands) {
  let answer = "";

  function getSecondTime(time) {
    const [mm, ss] = time.split(":").map((time) => parseInt(time, 10));
    return mm * 60 + ss;
  }

  const videoTime = getSecondTime(video_len);
  let currentTime = getSecondTime(pos);
  const opStartTime = getSecondTime(op_start);
  const opEndTime = getSecondTime(op_end);

  const controlTime = {
    prev: -10,
    next: 10,
  };

  for (let x of commands) {
    if (opStartTime <= currentTime && opEndTime >= currentTime)
      currentTime = opEndTime;
    if (currentTime < 0) currentTime = 0;
    if (currentTime > videoTime) currentTime = videoTime;
    currentTime = currentTime + controlTime[x];
    if (opStartTime <= currentTime && opEndTime >= currentTime)
      currentTime = opEndTime;
    if (currentTime < 0) currentTime = 0;
    if (currentTime > videoTime) currentTime = videoTime;
  }

  const min = Math.floor(currentTime / 60); //소수점 밑으로는 필요없으니 내림처리
  const sec = currentTime % 60;
  answer = `${String(min).padStart(2, "0")}:${String(sec).padStart(2, "0")}`;

  return answer;
}

🛠️ 리팩터링

그런데 중복되는 부분도 많고 지저분해 보인다. 리팩터링해보자.


function solution(video_len, pos, op_start, op_end, commands) {
  function getSecondTime(time) {
    const [mm, ss] = time.split(":").map((time) => parseInt(time, 10));
    return mm * 60 + ss;
  }

  const videoTime = getSecondTime(video_len);
  let currentTime = getSecondTime(pos);
  const opStartTime = getSecondTime(op_start);
  const opEndTime = getSecondTime(op_end);

  function checkCurrentTime(time) {
    if (opStartTime <= time && opEndTime >= time) return opEndTime;
    return Math.max(0, Math.min(time, videoTime));
  }

  const controlTime = {
    prev: -10,
    next: 10,
  };

  for (let x of commands) {
    currentTime = checkCurrentTime(currentTime);
    currentTime += controlTime[x];
    currentTime = checkCurrentTime(currentTime);
  }

  const min = String(Math.floor(currentTime / 60)).padStart(2, "0"); //소수점 밑으로는 필요없으니 내림처리
  const sec = String(currentTime % 60).padStart(2, "0");

  return `${min}:${sec}`;
}

🤔 다른 풀이1 (이전 앞 오류 문제 풀이)

기존 풀이가 그렇게 잘못된 건 아닌것 같아 다시 천천히 보니 검사 로직의 순서가 잘못됐었다. 가장 중요한 것은 변경값이 오프닝 구간에 들어가면 끝으로 가야하니 video 길이 비교랑 순서를 바꿨어야했다...
아까워서 기존 풀이 정답을 리팩터링해서 넣어봤다..

function solution(video_len, pos, op_start, op_end, commands) {
  function getSecondTime(time) {
    const [mm, ss] = time.split(":").map(Number);
    return mm * 60 + ss;
  }

  let currentTime = getSecondTime(pos);
  const videoTime = getSecondTime(video_len);
  const opStartTime = getSecondTime(op_start);
  const opEndTime = getSecondTime(op_end);

  if (opStartTime <= currentTime && opEndTime >= currentTime)
    currentTime = opEndTime;

  for (let x of commands) {
    currentTime += x === "next" ? 10 : -10;
    currentTime = Math.max(0, Math.min(currentTime, videoTime));
    if (opStartTime <= currentTime && opEndTime >= currentTime)
      currentTime = opEndTime;
  }

  const min = String(Math.floor(currentTime / 60)).padStart(2, "0"); //소수점 밑으로는 필요없으니 내림처리
  const sec = String(currentTime % 60).padStart(2, "0");

  return `${min}:${sec}`;
}

🧑‍💻 마무리

순서만 바꿔도 정답이었는데 이렇게 중점 파악 능력이 중요하다...
연습밖에 답이 없다.

📌 출처
프로그래머스 Lv.1 동영상 재생기

profile
osanThor⚡️블로그 이전했습니다. https://blog.given-log.com

0개의 댓글