JAVA/코딩테스트

프로그래머스 레벨 1 - 동영상 재생기[자바]

진짠 2024. 9. 7. 11:07
728x90
문제

 

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

 

시간의 흐름 순으로 이동하며 풀었습니다.

 

1 - 초기 pos가 오프닝 구간일 경우 건너뛰기 실행

2 - command 배열만큼 10초 뒤, 앞으로 이동

3 - 10초 뒤 이동했는데 동영상 시작시간보다 짧아질 경우 0분 0초로 변환

4 - 10초 앞으로 이동했는데 동영상 종료시간보다 길어질 경우 동영상 종료시간으로 변환

5 - 구간이동 후 오프닝 구간일 경우 건너뛰기 실행

 

그래서 저는 이렇게 풀었습니다.

 

import java.util.*;
class Solution {
    public String solution(String video_len, String pos, String op_start, String op_end, String[] commands) {
        int count = 0;
        
        pos = opening(op_start, op_end, pos); //초기 pos 오프닝 건너뛰기 실행
        while(count < commands.length) {
            String command = commands[count];
            pos = beforeSec(command, pos, op_start, op_end); //prev 로직 실행
            pos = afterSec(command, video_len, pos, op_start, op_end); //next 로직 실행
            pos = opening(op_start, op_end, pos); //구간 이동 후 오프닝 건너뛰기실행
            count++;
        }
        return pos;
    }
    
    private String opening(String op_start, String op_end, String pos) {
        String[] posSplit = pos.split(":");
        int posLength = Integer.parseInt(posSplit[0])*60 + Integer.parseInt(posSplit[1]);
        
        String[] osSplit = op_start.split(":");
        int osLength = Integer.parseInt(osSplit[0])*60 + Integer.parseInt(osSplit[1]);
        
        String[] oeSplit = op_end.split(":");
        int oeLength = Integer.parseInt(oeSplit[0])*60 + Integer.parseInt(oeSplit[1]);
        
        // pos가 오프닝 구간에 있다면 건너뛴다.
        if(posLength >= osLength && posLength < oeLength) {
            pos = op_end;
        }
        
        return pos;
    }
    
    private String beforeSec(String command, String pos, String op_start, String op_end) {
        if("prev".equals(command)) { //command가 prev면 재생 시간 10초 전으로 이동
           String[] timeSplit = pos.split(":");
            int m = Integer.parseInt(timeSplit[0]);
            int s = Integer.parseInt(timeSplit[1])-10;

            if(s<0) {
                m-=1;
                s+=60;
            }
            
            if(m<0) { //10초 뒤로 갔는데 시작시간보다 작다면 0분0초
                m=0;
                s=0;
            }
            
            String mm = m<10 ? "0"+m : ""+m;
            String ss = s<10 ? "0"+s : ""+s;
            
            pos = mm+":"+ss; 
        }
        return pos;
    }
    
    private String afterSec(String command, String video_len, String pos, String op_start, String op_end) {
        if("next".equals(command)) { //command가 next 재생 시간 10초 뒤로 이동
            String[] timeSplit = pos.split(":");
            int m = Integer.parseInt(timeSplit[0]);
            int s = Integer.parseInt(timeSplit[1])+10;

            if(s>=60) {
                m+=1;
                s-=60;
            }
            
            String[] videoSplit = video_len.split(":");
            int vm = Integer.parseInt(videoSplit[0]);
            int vs = Integer.parseInt(videoSplit[1]);
            if((vm == m && vs < s) || vm < m) { //10초 앞으로 갔는데 비디오길이보다 크다면 비디오 길이만큼
                m=vm;
                s=vs;
            }
            
            String mm = m<10 ? "0"+m : ""+m;
            String ss = s<10 ? "0"+s : ""+s;
            
            pos = mm+":"+ss; 
        }
        return pos;
    }
}

 

리팩토링

 

시간을 변환 부분에서 풀면서도 더 좋은 방법이 있을 것 같은데, 고민했습니다.

어느 부분에서는 mm:ss를 잘라서 하고, 어느 부분에서는 mm*60 + ss 로 해서 통일해서 풀면 좀 더 깔끔한 코드가 되지 않을까 생각했습니다.

 

import java.util.*;
class Solution {
    public String solution(String video_len, String pos, String op_start, String op_end, String[] commands) {
        int count = 0;
        int convertPos = timeConvertInt(pos);
        
        //초기 pos 오프닝 건너뛰기 실행
        convertPos = opening(op_start, op_end, convertPos); 
        while(count < commands.length) {
            String command = commands[count];
            //prev 로직 실행
            convertPos = beforeSec(command, convertPos, op_start, op_end); 
            //next 로직 실행
            convertPos = afterSec(command, video_len, convertPos, op_start, op_end);
            //구간 이동 후 오프닝 건너뛰기실행
            convertPos = opening(op_start, op_end, convertPos); 
            count++;
        }
        
        return intConvertTime(convertPos);
    }
    
    private int opening(String op_start, String op_end, int convertPos) {
        int osLength = timeConvertInt(op_start);
        int oeLength = timeConvertInt(op_end);
        
        // pos가 오프닝 구간에 있다면 건너뛴다.
        if(convertPos >= osLength && convertPos < oeLength) {
            convertPos = oeLength;
        }
        
        return convertPos;
    }
    
    private int beforeSec(String command, int convertPos, String op_start, String op_end) {
        //command가 prev면 재생 시간 10초 전으로 이동
        if("prev".equals(command)) { 
           convertPos-= 10;
            
            //10초 뒤로 갔는데 시작시간보다 작다면 0분0초
            if(convertPos<0) { 
                convertPos = 0;
            }
            
            return convertPos;
        }
        
        return convertPos;
    }
    
    private int afterSec(String command, String video_len, int convertPos, String op_start, String op_end) {
        //command가 next 재생 시간 10초 뒤로 이동
        if("next".equals(command)) { 
            convertPos += 10;            
            int videoLength = timeConvertInt(video_len);
            
            //10초 앞으로 갔는데 비디오길이보다 크다면 비디오 길이만큼
            if(convertPos > videoLength) { 
                convertPos = videoLength;
            }
            
            return convertPos;
        }
        
        return convertPos;
    }
    
    private int timeConvertInt(String time) {
        String[] timeSplit = time.split(":");
        int mm = Integer.parseInt(timeSplit[0]);
        int ss = Integer.parseInt(timeSplit[01]);
        
        return mm * 60 + ss;
    }
    
    private String intConvertTime(int time) {
        int mm = time / 60;
        int ss = time % 60;
        
        return String.format("%02d:%02d", mm, ss);
    }
}

 

결과

 

time convert용 메소드를 만들어서 시간 계산을 int값으로 통일했습니다. 나중에 값 출력할때만 다시 포맷을 변경하여 출력하도록 수정했습니다. 

코드 개수도 줄었고 가독성도 좋아졌으며 테스트 돌린 결과 성능도 10배가량 향상되었습니다.

아마 불필요한 분기처리문(초가 60초이상이면 분을 올린다던가)을 빼고 숫자계산으로 통일하니 그런 것 같습니다.

728x90