[프로그래머스] 동영상 재생기

지원·2025년 2월 27일
0

Algorithm

목록 보기
3/6
post-thumbnail

[PCCP 기출문제] 1번 / 동영상 재생기

문제

당신은 동영상 재생기를 만들고 있습니다. 당신의 동영상 재생기는 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_lenposop_startop_end는 "mm:ss" 형식으로 mm분 ss초를 나타냅니다.
    • 0 ≤ mm ≤ 59
    • 0 ≤ ss ≤ 59
    • 분, 초가 한 자리일 경우 0을 붙여 두 자리로 나타냅니다.
    • 비디오의 현재 위치 혹은 오프닝이 끝나는 시각이 동영상의 범위 밖인 경우는 주어지지 않습니다.
    • 오프닝이 시작하는 시각은 항상 오프닝이 끝나는 시각보다 전입니다.
  • 1 ≤ commands의 길이 ≤ 100
    • commands의 원소는 "prev" 혹은 "next"입니다.
    • "prev"는 10초 전으로 이동하는 명령입니다.
    • "next"는 10초 후로 이동하는 명령입니다.

입출력 예

video_lenposop_startop_endcommandsresult
"34:33""13:00""00:55""02:55"["next", "prev"]"13:00"
"10:55""00:05""00:15""06:55"["prev", "next", "next"]"06:55"
"07:22""04:05""00:15""04:07"["next"]"04:17"

풀이

  • min을 sec으로 바꿔 안정적으로 계산
// 1. pos가 op_start <= pos <= op_end 일시 바로 op_end로 이동
// 2. 명령어에 따라 prev 일시 10초 전 next일시 10초 후로 이동
// 2-1. 만약 커맨드 실행 후 op 구간일 경우 op_end로 이동한다
// 2-2. 이후 초가 60초가 넘어가면 분에 1을 더하고 초는 60의 나머지로 설정
// 2-3. 초가 0초 미만이면 분에 1 빼고 초는 그 차이만큼 60에서 빼기
// 3. 커맨드 실행 결과가 video_len을 넘어가면 결과는 video_len이 된다
// 4. 커맨드 실행 결과 10초 미만일 경우 처음 위치로 이동
// 5. 커맨드 실행 결과 남은 시간이 10초 미만일 땐 마지막 위치로 이동

function solution(video_len, pos, op_start, op_end, commands) {
    const [r_min, r_sec] = video_len.split(':').map(Number); // 비디오 길이
    const [s_min, s_sec] = op_start.split(':').map(Number); // op_start 분 초
    const [e_min, e_sec] = op_end.split(':').map(Number); // op_end 분 초
    let [c_min, c_sec] = pos.split(':').map(Number); // 현재 분 초
    
    // 비디오 길이(초 단위)
    const videoLengthSeconds = r_min * 60 + r_sec;

    // (1)초기 위치가 op 구간인지 확인
    [c_min, c_sec] = check(s_min, s_sec, e_min, e_sec, c_min, c_sec);
    
    for (const cmd of commands) {
        if (cmd === 'next') {
            // 현재 위치 초 단위로 변환
            const currentSeconds = c_min * 60 + c_sec;
            // 남은 시간 계산
            const remainingSeconds = videoLengthSeconds - currentSeconds;
            
            if (remainingSeconds < 10) {
                // (5)남은 시간이 10초 미만이면 영상 끝으로 이동
                c_min = r_min;
                c_sec = r_sec;
            } else {
                // 10초 후로 이동
                c_sec += 10;
                if (c_sec >= 60) {
                    c_min += 1;
                    c_sec %= 60;
                }
                
                // 비디오 길이 초과 체크
                const newSeconds = c_min * 60 + c_sec;
                if (newSeconds > videoLengthSeconds) {
                    c_min = r_min;
                    c_sec = r_sec;
                }
            }
        } else if (cmd === 'prev') {
            // 현재 위치 초 단위로 변환
            const currentSeconds = c_min * 60 + c_sec;
            
            if (currentSeconds < 10) {
                // (4) 현재 위치가 10초 미만이면 처음으로 이동
                c_min = 0;
                c_sec = 0;
            } else {
                // 10초 전으로 이동
                const newSeconds = currentSeconds - 10;
                c_min = Math.floor(newSeconds / 60);
                c_sec = newSeconds % 60;
            }
        }
        
        // (2-1) op 구간 확인
        [c_min, c_sec] = check(s_min, s_sec, e_min, e_sec, c_min, c_sec);
    }

    return formatTime(c_min, c_sec);
}

function check(s_min, s_sec, e_min, e_sec, c_min, c_sec) {
    // 현재 시간, 시작 시간, 끝 시간을 초 단위로 변환
    const currentSec = c_min * 60 + c_sec;
    const startSec = s_min * 60 + s_sec;
    const endSec = e_min * 60 + e_sec;
    
    // (2-1) op 구간에 있는지 확인 
    if (currentSec >= startSec && currentSec <= endSec) {
        return [e_min, e_sec]; // op 구간에 있으면 op_end로 이동
    }
    
    return [c_min, c_sec]; // 그렇지 않으면 현재 위치 유지
}

function formatTime(min, sec) {
		// 시간 표기에 맞게 형식 변경
    return `${min.toString().padStart(2, '0')}:${sec.toString().padStart(2, '0')}`;
}

❓ padStart

  • JavaScript의 문자열 메서드
  • 현재 문자열의 길이가 지정한 길이보다 작을 경우 문자열의 시작 부분에 특정 문자를 채워 넣는 기능을 한다
  • 틀렸던 풀이
    function solution(video_len, pos, op_start, op_end, commands) {
        var answer = '';
        const [r_min, r_sec] = video_len.split(':'); // 비디오 길이
        const [s_min, s_sec] = op_start.split(':'); // op_start 분 초
        const [e_min, e_sec] = op_end.split(':'); // op_end 분 초
        let [c_min, c_sec] = pos.split(':'); // 현재 분 초
    
        [c_min, c_sec] = check(s_min, s_sec, e_min, e_sec, c_min, c_sec)
        
        if (is_end(r_min, r_sec, c_min, c_sec)) return `${c_min}:${c_sec}`
    
        commands.forEach(c => {
            [c_min, c_sec] = cmd_processing(c, c_min, c_sec)
            [c_min, c_sec] = check(s_min, s_sec, e_min, e_sec, c_min, c_sec)
            if (is_end) return `${c_min}:${c_sec}`
        });
    
        return `${c_min}:${c_sec}`;
    }
    
    function cmd_processing(cmd, min, sec) {
        let result_min = min;
        let result_sec = sec;
        if (cmd === 'prev') {
            result_sec -= sec - 10;
            if (result_sec < 0) {
                result_min -= 1;
                result_sec = 60 - sec;
            } 
        } else if (cmd === 'next') {
          result_sec = sec + 10;
          if (result_sec > 60) {
            result_min += 1;
            result_sec %= 60;
          }  
        }
        return [result_min, result_sec]
    }
    
    function check(s_min, s_sec, e_min, e_sec, c_min, c_sec) {
        if (s_min <= c_min <= e_min && s_sec <= c_sec <= e_sec) {
            return [e_min, e_sec]
        }
    }
    
    function is_end(r_min, r_sec, c_min, c_sec) {
        if (r_min === c_min && r_sec === c_sec) {
            return true
        } else return false
    }
    
    console.log(solution("34:33", "13:00", "00:55", "02:55", ["next", "prev"]))
    • min과 sec을 따로 관리하여 더 복잡했었다
    • 4, 5번 요구사항을 구현하지 못했었다
    • 아래와 같은 비교식이 javaScript에서 사용 불가능하다는 점을 타 언어와 헷갈렸다 😥
      s_min <= c_min <= e_min
profile
Cat is cute and development is endless

0개의 댓글