문제 설명
당신은 동영상 재생기를 만들고 있습니다. 당신의 동영상 재생기는 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"의 형식으로 mm분 ss초를 나타냅니다.
- 0<=mm<=59
- 0<=ss<=59
- 분, 초가 한 자리일 경우 0을 붙여 두 자리로 나타냅니다.
- 비디오의 현재 위치 혹은 오프닝이 끝나는 시각이 동영상의 범위 밖인 경우는 주어지지 않습니다.
- 오프닝이 시작하는 시각은 항상 오프닝이 끝나는 시각보다 전입니다.
- 1<=commands의 길이<=100
- commands의 원소는 "prev" 혹은 "next" 입니다.
- "prev"는 10초 전으로 이동하는 명령입니다.
- "next"는 10초 후로 이동하는 명령입니다.
입출력 예
video_len | pos | op_start | op_end | commands | result | 설명 | ||
"34:33" | "13:00" | "00:55" | "02:55" | ["next", "prev"] | "13:00" | 시작 위치 13분 0초에서 10초 후로 이동하면 13분 10초입니다. 13분 10초에서 10초 전으로 이동하면 13분 0초입니다. 따라서 "13:00"을 return 하면 됩니다. |
||
"10:55" | "00:05" | "00:15" | "06:55" | ["prev", "next", "next"] | "06:55" | 시작 위치 0분 5초에서 10초 전으로 이동합니다. 현재 위치가 10초 미만이기 때문에 0분 0초로 이동합니다. 0분 0초에서 10초 후로 이동하면 0분 10초입니다. 0분 10초에서 10초 후로 디오하면 0분 20초입니다. 0분 20초는 오프닝 구간이기 때문에 오프닝이 끝나는 위치인 6분 55초로 이동합니다. 따라서 "06:55"를 return 하면 됩니다. |
||
"07:22" | "04:05" | "00:15" | "04:07" | ["next"] | "04:17" | 시작 위치 4분 5초는 오프닝 구간이기 때문에 오프닝이 끝나는 위치인 4분 7초로 이동합니다. 4분 7초에서 10초 후로 이동하면 4분 17초입니다. 따라서 "04:17"을 return 하면 됩니다. |
문제 풀이
풀이 언어 : C++
#include <string>
#include <vector>
using namespace std;
// String형 분/초 -> 초 변환
// : "mm:ss" String형으로 나타낸 분과 초를 초로 변환한다.
int StringChangeToSeconds(string minute_seconds)
{
int minute=stoi(minute_seconds.substr(0, 2));
int seconds=stoi(minute_seconds.substr(3, 2));
return minute*60+seconds;
}
// 오프닝 구간인지 확인하고 건너뛰기
// : 오프닝 구간인지 확인하고 오프닝 구간이라면 오프닝이 끝나는 위치를 반환하고 아니라면 그냥 현재 위치를 반환한다.
int CheckOpening(int op_start_seconds, int op_end_seconds, int pos_seconds)
{
if((pos_seconds<=op_end_seconds)&&(pos_seconds>=op_start_seconds))
{
return op_end_seconds;
}
else
{
return pos_seconds;
}
}
// 초 -> 분/초 String 표현 변환
// : 초를 받아와 mm:ss 의 String 표현으로 변환하여 반환한다.
string SecondsChangeToString(int pos_seconds)
{
string sMinutes="";
string sSeconds="";
if(pos_seconds/60<10)
{
sMinutes="0"+to_string(pos_seconds/60);
}
else
{
sMinutes=to_string(pos_seconds/60);
}
if(pos_seconds%60<10)
{
sSeconds="0"+to_string(pos_seconds%60);
}
else
{
sSeconds=to_string(pos_seconds%60);
}
return sMinutes+":"+sSeconds;
}
string solution(string video_len, string pos, string op_start, string op_end, vector<string> commands) {
string answer = "";
// 매개변수 정수형 초로 변환
int pos_seconds=StringChangeToSeconds(pos); // pos
int video_len_seconds=StringChangeToSeconds(video_len); // video_len
int op_start_seconds=StringChangeToSeconds(op_start); // op_start
int op_end_seconds=StringChangeToSeconds(op_end); // op_end
// 오프닝 건너뛰기
pos_seconds=CheckOpening(op_start_seconds, op_end_seconds, pos_seconds);
// commands로 들어온 명령 수행하기
for(int i=0; i<commands.size(); i++)
{
if(commands[i]=="prev") // 10초 전으로 이동 명령
{
// 현재 위치가 10초 미만인 경우
if(pos_seconds<10)
{
pos_seconds=0; // 영상의 처음 위치로 이동
} // 현재 위치가 10초 이상인 경우
else
{
pos_seconds-=10; // 재생 위치에서 10초 전으로 이동
}
// 오프닝 건너뛰기
pos_seconds=CheckOpening(op_start_seconds, op_end_seconds, pos_seconds);
}
else if(commands[i]=="next") // 10초 후로 이동 명령
{
// 남은 시간이 10초 미만일 경우
if(video_len_seconds-pos_seconds<10)
{
// 영상의 마지막 위치로 이동
pos_seconds=video_len_seconds;
}
else // 남은 시간이 10초 이상일 경우
{
pos_seconds+=10; // 재생 위치에서 10초 후로 이동
}
// 오프닝 건너뛰기
pos_seconds=CheckOpening(op_start_seconds, op_end_seconds, pos_seconds);
}
}
// 정수형 초를 문자열로 전환
answer=SecondsChangeToString(pos_seconds);
return answer;
}
일단 이 문제의 시작은 주어진 매개변수를 그대로 사용하지 않을 결심을 하는 것부터 시작이다. 시간을 계산해야하는 문제에서 string 데이터 타입을 사용하는 것은 매우 어렵다. 그리고 숫자로 되어 있다고 하더라도 분과 초가 따로 나누어져 있는 형태는 계산에 활용하기 어려운 형태이다. 따라서 일단 "mm:ss" 형식의 string 데이터를 초로만 나타내게 해야한다.
StringChangeToSeconds(string minute_seconds) 함수를 정의하여 "mm:ss" 형태의 string 데이터에서 분과 초를 뽑아내고 초로 변환한다. substr() 함수를 이용하여 mm, ss부분만 따로 뽑아내고 각각을 stoi를 이용해 정수형으로 만들어준다. minute와 seconds를 각각 뽑아낸 후 minute*60+seconds를 계산하여 반환한다. 이렇게하면 분과 초로 나누어져 있던 시간을 초로 바꿀 수 있다.
commands를 제외한 나머지 시간을 string형으로 받아오던 매개변수들을 전부 StringChangeToSeconds 함수를 이용해 계산할 수 있는 초로 바꿔준다.
시작하자마자 pos가 오프닝 구간에 있는지부터 확인해주어야 한다. 그런데 앞으로 오프닝 구간에 있는지 확인해줘야할 부분들이 많아서 이 것도 함수로 만들어 보겠다. CheckOpening(int op_start_seconds, int op_end_seconds, int pos_seconds) 함수를 작성한다. pos_second(현재 위치)가 op_start_seconds(오프닝 시작 초)와 op_end_seconds(오프닝 끝 초) 사이에 있다면 오프닝 구간에 있는 것이므로 op_end_seconds 값을 반환하고 오프닝 구간이 아니라면 그냥 현재 자신의 위치를 그대로 반환한다.
이 함수를 이용하여 main에서 pos_seconds를 업데이트한다. 오프닝 구간이면 오프닝 구간의 끝으로 업데이트되고 아니라면 아무 변화가 없는 것이다.
이제 commands의 명령을 수행할 때가 되었다. 반복문을 돌리며 commands안에 들어있는 모든 명령을 처리한다.
"prev"일 경우 10초 전으로 이동 해야 한다. 하지만 한 가지 확인해야할 사안은 현재 위치가 10초미만일 때다. 그럴 경우 시간이 음수로 넘어가기 때문에 이 경우는 따로 조건문을 이용해 빼서 pos_seconds를 동영상의 0초로 설정한다. 그 외의 경우에는 명령대로 pos_seconds에 -10을 한다. 처리가 끝나고 나서 오프닝 구간인지 확인도 잊지 않는다.
다음으로 "next"인 경우 10초 후로 이동해야 한다. 이 경우도 한 가지 경우를 확인해야 하는데 10초 후로 이동하니 영상 밖으로 튀어나갈 때이다. 즉 남은 시간이 10초 미만일 경우 영상의 마지막 위치, video_len_seconds로 현재 위치를 설정한다. 그렇지 않을 경우 재생 위치에서 10초 이동하도록 +10 한다. 이 때도 마찬가지로 오프닝 구간인지 확인한다.
마지막으로 여직 초로 계산하던 값을 다시 "mm:ss" 형태의 string 변수로 변환하면 된다. SecondsChangeToString(int pos_seconds) 함수를 작성하여 기능을 구현한다. pos_second/60을 하면 분이 나오고 pos_seconds%60을 하면 초가 나온다. 이 때 값이 한자리가 나오면 앞에 0을 붙여 두자리로 만들어주야 한다. 한 자리가 나오는 경우는 따로 빼서 0을 붙여주고 나머지 경우에는 to_string 함수를 이용하여 형변환 해준다.
마지막으로 반환 값을 (sMinutes+":"+sSeconds) 형태로 만들어주면 된다.
참고 사항
string의 멤버 변수인 substr(int i, int j)는 i번째 글자부터 j개의 글자를 뽑아 반환한다.
int StringChangeToSeconds(string minute_seconds)
{
int minute=stoi(minute_seconds.substr(0, 2));
int seconds=stoi(minute_seconds.substr(3, 2));
return minute*60+seconds;
}
오답 노트
오프닝 구간인지 확인하는 과정이 마지막에 한 번만 들어가면 되는 줄 알았는데 시간이 변할 때마다 확인해야 하는 과정임을 나중에 알고 수정하였다.
문제 링크
https://school.programmers.co.kr/learn/courses/30/lessons/340213
프로그래머스
SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프
programmers.co.kr
'Code KATA > 알고리즘 코드카타' 카테고리의 다른 글
[2024.12.31] [PCCP 기출문제] 2번 / 퍼즐 게임 챌린지 (0) | 2024.12.31 |
---|---|
[2024.12.31] 가운데 글자 가져오기 (1) | 2024.12.31 |
[2024.12.30] 제일 작은 수 제거하기 (1) | 2024.12.30 |
[2024.12.29] 없는 숫자 더하기 (3) | 2024.12.27 |
[2024.12.28] 핸드폰 번호 가리기 (0) | 2024.12.27 |