[프로그래머스 340213] 동영상 재생기 (Java)

codingNoob12·2026년 1월 11일

알고리즘

목록 보기
76/97

주말동안 간단하게 레벨 1 문제 플어보다가, 생각보다 괜찮은 문제가 있어서 가져와봤다.

그냥 현재 위치에서 nextprev명령어를 수행하도록 구현하되, 현재 위치가 오프닝 구간이면 스킵하는 로직을 작성하면 된다.

정말 간단한 문제라, 처음엔 LocalDateTime이나 LocalTime을 이용하려고 했는데, DateTimeFormatter 설정이 조금 복잡해질 것 같아서, 이 방법은 패스했다.

이제 로직을 구현해서 풀려고 하는데, 이 문제 특성상 데이터를 분과 초를 묶어서 관리해야하므로, 클래스 도입이 필수였다.

막상 클래스를 만들어놓고 보니, 문자열로부터 파싱을 해야하므로 팩토리메서드 패턴을 도입하기로 했고, String타입으로 답을 내야하므로 toString메서드까지 구현하기로 했다.

그리고, 동영상 재생기가 제공하는 기능들은 결국 시간을 다루는 기능들이기 때문에 내가 만든 Time클래스에 메서드로 추가하는 것이 좋아보였다.

기능들을 구현하면서, compareTotoTotalSeconds메서드가 필요하다 판단한 이유는 isInRange메서드 때문이였다. 근데, 구현하면서 toTotalSeconds는 생각보다 유용해서 previous, next메서드에서도 사용했다.

아래는 구현된 코드이다.

class Solution {
    public String solution(String video_len, String pos, String op_start, String op_end, String[] commands) {
        Time current = Time.from(pos);
        Time videoEnd = Time.from(video_len);
        Time opStart = Time.from(op_start);
        Time opEnd = Time.from(op_end);
        for (String command : commands) {
            current = current.skipOpening(opStart, opEnd);

            if (command.equals("prev")) {
                current = current.previous();
            } else if (command.equals("next")) {
                current = current.next(videoEnd);
            }
        }
        return current.skipOpening(opStart, opEnd).toString();
    }

    static class Time implements Comparable<Time> {
        int minutes;
        int seconds;

        private Time(int minutes, int seconds) {
            this.minutes = minutes;
            this.seconds = seconds;
        }

        /**
         * "mm:ss" 형식의 문자열을 Time 타입으로 변환하는 팩토리 메서드
         * 
         * @param time "mm:ss" 형식을 만족하는 문자열
         * @return 해당 시간의 Time
         */
        public static Time from(String time) {
            String[] parts = time.split(":");
            return new Time(Integer.valueOf(parts[0]), Integer.valueOf(parts[1]));
        }

        /**
         * 10초 전으로 이동합니다. 만약, 10초 미만일 경우 처음 위치로 이동합니다.
         * 
         * @return 10초 미만일 경우 처음 위치 리턴, 10초 미만이 아닐 경우 10초 전 위치 리턴
         */
        public Time previous() {
            int totalSeconds = this.toTotalSeconds();
            totalSeconds -= 10;
            if (totalSeconds < 0) {
                totalSeconds = 0;
            }
            return new Time(totalSeconds / 60, totalSeconds % 60);
        }

        /**
         * 10초 후로 이동합니다. 남은 시간이 10초 미만일 경우 영상 마지막 위치로 이동
         * 
         * @param end 영상의 마지막 위치
         * @return 남은 시간이 10초 미만일 경우 영상 마지막 위치 리턴, 10초 미만이 아닐 경우 10초 후 위치 리턴
         */
        public Time next(Time end) {
            int totalSeconds = this.toTotalSeconds();
            totalSeconds += 10;
            if (end.toTotalSeconds() < totalSeconds) {
                return end;
            }
            return new Time(totalSeconds / 60, totalSeconds % 60);
        }

        /**
         * 현재 재생 위치가 오프닝 구간이면 오프닝이 끝나는 위치로 이동
         * 
         * @param start 오프닝 시작 위치
         * @param end   오프닝 끝 위치
         * @return 오프닝 구간인 경우 오프닝 끝 위치 리턴, 아닌 경우 현재 위치 리턴
         */
        public Time skipOpening(Time start, Time end) {
            if (isInRange(start, end)) {
                return end;
            }
            return this;
        }

        @Override
        public String toString() {
            return String.format("%02d:%02d", this.minutes, this.seconds);
        }

        @Override
        public int compareTo(Time that) {
            return Integer.compare(this.toTotalSeconds(), that.toTotalSeconds());
        }

        /**
         * 현재 시간을 초단위로 바꿔주는 함수. compareTo 때문에 내부적으로 구현
         * 
         * @return totalSeconds
         */
        private int toTotalSeconds() {
            return this.minutes * 60 + this.seconds;
        }

        /**
         * 현재 시간이 주어진 범위 내에 있는지 판단하는 함수
         * 
         * @param start 시작 시간 (inclusive)
         * @param end   끝 시간 (inclusive)
         * @return 범위 내에 있으면 true 리턴, 범위 밖에 있으면 false 리턴
         */
        private boolean isInRange(Time start, Time end) {
            return this.compareTo(start) >= 0 && this.compareTo(end) <= 0;
        }
    }
}

생각보다 퀄리티 있는 코드를 짜서 기분 좋았고, 이렇게 코드 짜니까 유지보수가 편해서 손쉽게 문제를 해결했다.
다만, 성능상의 오버헤드가 다소 있는 것이 거슬리지만, 이 문제는 단순 구현 문제라 유지보수성이 높은 코드가 이점이 더 높아 보여서 객체지향적 설계로 접근하는 것이 좋아보인다.

profile
나는감자

0개의 댓글