
📑 1. 문제설명




💡 2. 접근방식
만들어줄 메서드는 4가지
- 오프닝 끝 위치로 이동하는 `SkipOp()` 메서드
- 명령이 "next" 이면 10초 뒤로 이동하는 `moveToNext()`메서드
- 명령이 "prev" 이면 10초 앞으로 이동하는 `moveToPrev()` 메서드
- String 타입으로 입력 받은 시간을 LocalTime으로 형변환 하는 `getTime()`메서드
"mm:ss" 형식으로 받아온 시간을 ":" 기준으로 분, 초 단위로 나누어 배열에 저장한다.
LocalTime이 가진 메서드로 시간 계산을 하고, 반환할 때는 다시 "mm:ss" 형식으로 포매팅 해서 반환해 주어야 함.
현재 시간이 오프닝 위치 안에 있을 때는 자동으로 SkipOp() 메서드가 호출된다.
⭐ 3. 정답코드
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
class Solution {
private LocalTime videoTime;
private LocalTime posTime;
private LocalTime opStartTime;
private LocalTime opEndTime;
public String solution(String video_len, String pos, String op_start,
String op_end, String[] commands) {
// 시간 문자열 분리
String videoSplit[] = video_len.split(":");
String posSplit[] = pos.split(":");
String opStart[] = op_start.split(":");
String opEnd[] = op_end.split(":");
// LocalTime으로 변환
videoTime = getTime(videoSplit); // 전체 동영상 시간
posTime = getTime(posSplit); // 현재 재생 위치
opStartTime = getTime(opStart); // 오프닝 시작 위치
opEndTime = getTime(opEnd); // 오프닝 끝 위치
// 처음 재생 시 오프닝 스킵
skipOp();
// 명령어 처리
for (String command : commands) {
if (command.equals("prev")) {
moveToPrev();
} else if (command.equals("next")) {
moveToNext();
}
skipOp();
}
// 현재 재생 시간을 "mm:ss" 형식으로 반환(패딩처리)
return posTime.format(DateTimeFormatter.ofPattern("mm:ss"));
}
// 10초 뒤로 이동하는 메서드
private void moveToNext() {
posTime = posTime.plusSeconds(10);
if (posTime.isAfter(videoTime)) {
posTime = videoTime; // 동영상 끝 시간을 초과하지 않도록 설정
}
}
// 10초 앞으로 이동하는 메서드
private void moveToPrev() {
int minute = posTime.getMinute();
int second = posTime.getSecond();
if (minute == 0 && second < 10) {
posTime = LocalTime.of(0, 0, 0); // 0초 미만으로 이동하면 00:00으로 설정
return;
}
posTime = posTime.minusSeconds(10);
}
// 오프닝 스킵 메서드
private void skipOp() {
if (!posTime.isBefore(opStartTime) && !posTime.isAfter(opEndTime)) {
posTime = opEndTime; // 오프닝 시간 내에 있으면 오프닝 끝으로 이동
}
}
// 문자열로 표현된 시간을 LocalTime 타입으로 변환하는 메서드
private LocalTime getTime(String[] split) {
int min = Integer.parseInt(split[0]);
int sec = Integer.parseInt(split[1]);
return LocalTime.of(0, min, sec);
}
}
+ 테스트 코드
public static void main(String[] args) {
Solution sol = new Solution();
// 테스트 입력
String videoLen = "10:00"; // 동영상 길이
String pos = "00:05"; // 초기 재생 위치
String opStart = "00:10"; // 오프닝 시작 시간
String opEnd = "00:20"; // 오프닝 끝 시간
String[] commands = {"next", "next", "prev", "next"}; // 명령어 배열
// 결과 출력
System.out.println(sol.solution(videoLen, pos, opStart, opEnd, commands));
// 예상 출력: "00:30"
}
여러번 틀린 끝에 드디어...!
시행착오가 많아서 코드를 한 10번은 고친 것 같다.
처음 재생 시 오프닝 스킵 skipOp(); 이건 왜 하나?
처음 재생 시 skipOp()를 호출하는 이유는 재생 위치가 처음부터 오프닝 범위 안에 있을 수 있기 때문이다. 만약 초기 pos가 오프닝 범위(op_start ~ op_end)에 포함된다면, 사용자가 아무 명령어를 입력하지 않더라도 재생 위치를 오프닝 끝으로 이동시켜야 하기 때문에 일단 skipOp() 호출 해 주어야 한다.
패딩을 처리하는 올바른 방법
DateTimeFormatter.ofPattern("mm:ss")을 사용해야 한다.그래야만 항상 두 자릿수의 "mm:ss" 형식이 유지된다.
DateTimeFormatter를 사용하지 않고 그냥 숫자 그대로 가져다 쓰면 아래처럼 된다.
public String formatTime(LocalTime time) {
int minutes = time.getMinute();
int seconds = time.getSecond();
return minutes + ":" + seconds; // 잘못된 패딩 처리
}
예시 결과
00:05 → 5:3
00:30 → 30:0
직접 문자열로 변환해도 마찬가지로 시간 형태가 일정하지 않음...
import java.time.LocalTime;
public class Solution {
public static void main(String[] args) {
LocalTime time1 = LocalTime.of(0, 5, 3); // 5분 3초
LocalTime time2 = LocalTime.of(0, 15, 30); // 15분 30초
// 패딩 없이 출력
System.out.println("time1: " + time1.toString()); // 기본 toString() 사용
System.out.println("time2: " + time2.toString());
}
}
출력 결과
time1: 00:05:03
time2: 00:15:30
Java LocalTime 클래스 메서드 정리
LocalTime.of(시간, 분, 초)
24시간제로 특정 시각을 생성하는 팩토리 메서드. (시간, 분, 초를 지정)
초는 생략 가능
LocalTime time1 = LocalTime.of(14, 30); // 오후 2시 30분
LocalTime time2 = LocalTime.of(14, 30, 45); // 오후 2시 30분 45초
System.out.println(time1); // 14:30
System.out.println(time2); // 14:30:45
isBefore / isAfter
현재 LocalTime 객체가 다른 시간보다 이전인지 / 이후인지 확인.
boolean isBefore(LocalTime otherTime);
boolean isAfter(LocalTime otherTime);
LocalTime time1 = LocalTime.of(10, 30);
LocalTime time2 = LocalTime.of(12, 45);
System.out.println(time1.isBefore(time2)); // true
System.out.println(time2.isBefore(time1)); // false
ateTimeFormatter.ofPattern
LocalTime 객체를 특정 형식의 문자열로 변환
포맷 형식은 예를 들면 "HH:mm", "mm:ss", "HH:mm:ss" 등이 있음.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(String pattern);
LocalTime time = LocalTime.of(9, 5, 30);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss");
System.out.println(time.format(formatter)); // 09:05:30
plusSeconds / minusSecond
현재 LocalTime 객체에서 지정한 초만큼 더하거나 뺀 새로운 시간 반환.
객체는 불변(immutable)하므로 원래 객체는 변하지 않고 새 객체를 반환.
초 단위로 더함. (분/시로 넘어가면 자동으로 계산)
좋아요 가장 많이 받은 코드
class Solution {
public int convertToSeconds(String time) {
String[] split = time.split(":");
return Integer.parseInt(split[0]) * 60 + Integer.parseInt(split[1]);
}
public String solution(String video_len, String pos, String op_start,
String op_end, String[] commands) {
// 각 시간들 초로 변환
int videoLenSec = convertToSeconds(video_len),
posSec = convertToSeconds(pos),
opStartSec = convertToSeconds(op_start),
opEndSec = convertToSeconds(op_end);
if (posSec >= opStartSec && posSec <= opEndSec) posSec = opEndSec;
// 시작 값 오프닝 구간 확인
for (String command : commands) {
if (command.equals("next")) posSec
= posSec + 10 >= videoLenSec ? videoLenSec : posSec + 10;
else posSec = posSec - 10 > 0 ? posSec - 10 : 0;
if (posSec >= opStartSec && posSec <= opEndSec) posSec = opEndSec;
// 오프닝 구간 확인
}
int m = posSec / 60,
s = posSec % 60;
String answer = ""; // StringBuilder 쓸정도 아님
answer += m < 10 ? "0" + m : m + "";
answer += ":";
answer += s < 10 ? "0" + s : s + "";
return answer;
}
}
🐦 4. 오답정리
내가 틀린 부분들
1. String opEnd[] = op_end.split(":"); 여기서 불필요한 공백 추가한거 `" : "` → `":"` 로 수정
2. 메서드 오타 수정 `skipOP()` → `skipOp()`로 변경.
3. moveToPrev 계산 오류 수정해 줌. posTime.minusSeconds(10);의 결과를 변수에 할당하지 않음. posTime 변수에 할당 해 줌.
4. 처음에 메서드나 변수 앞에 static 키워드를 남발 했기 때문에 불필요한 static은 제거해 주었다. 솔직히 아직도 명쾌하게는 모르겠다. 언제 static 쓰고 언제 안 쓰는지, static이 공유메모리인거는 아는데,,,
5. DateTimeFormatter.ofPattern("mm:ss") 에서 오타 수정 `Fomatter` → `Formatter`
6. LocalTime 생성자 잘못 사용`LocalTime(0, 0, 0)` → `LocalTime.of(0, 0, 0)`
7. 정의되지 않은 변수명인 `min` 사용. moveToPrev() 메서드에서 min이라는 변수를 사용했는데, 실제로 내가 선언한 변수 이름은 minute였다. 평소에 분은 min이라고 선언하다 보니 if 조건문에서 `min == 0`이라고 잘못 사용했다. 해당 부분을 `minute == 0`로 수정해 주었다.
8. Solution 클래스 바깥에 main 영역 만들어서 코드 테스트 돌려보았으나 했는데 프로그래머스 자체 에서는 안 됨
메서드만 잘 찾아서 쓰면 어려울 건 없지만, 코드가 너무 길어서 힘들었다.