Lv2 - 과제 제출하기
프로그래머스
코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.
programmers.co.kr
문제 해석
과제를 받은 루는 다음과 같은 순서대로 과제를 하려고 계획을 세웠습니다.
- 과제는 시작하기로 한 시각이 되면 시작합니다.
- 새로운 과제를 시작할 시각이 되었을 때, 기존에 진행 중이던 과제가 있다면 진행 중이던 과제를 멈추고 새로운 과제를 시작합니다.
- 진행중이던 과제를 끝냈을 때, 잠시 멈춘 과제가 있다면, 멈춰둔 과제를 이어서 진행합니다.
- 만약, 과제를 끝낸 시각에 새로 시작해야 되는 과제와 잠시 멈춰둔 과제가 모두 있다면, 새로 시작해야 하는 과제부터 진행합니다
- 멈춰둔 과제가 여러 개일 경우, 가장 최근에 멈춘 과제부터 시작합니다.
과제 계획을 담은 이차원 문자열 배열 plans가 매개변수로 주어질 때, 과제를 끝낸 순서대로 이름을 배열에 담아 return 하는 solution 함수를 완성해주세요.
풀이 방법
풀이 접근 과정
처음엔 그냥 순서대로 작업하면 되는 줄 알고, 큐를 사용하여 해결하지 못한 애들을 뒤로 보낼까 생각했다.
그런데 중간 작업이 멈추고 최근 멈춘 작업을 이어 한다는 조건을 보고 멈춘 작업을 따로 배열로 빼기로 했다.
이 때 스택을 사용했어도 됐지만, 귀찮으니까 그냥 arraylist로 작업 !!
다음 과제 시작 시간과 현재 과제 시작시간의 차이를 playtime과 비교하여 중단 과제 배열에 넣어 계산하도록 하였다.
최종 소스코드
class Solution {
fun solution(plans: Array<Array<String>>): Array<String> {
val answer = arrayListOf<String>()
val ing = arrayListOf<Array<String>>()
plans.sortWith(compareBy { it[1] })
for (i in 1 until plans.size) {
/* 1. 다음 과제 시작 시간과 현재 과제 시작시간의 차이를 playtime과 비교 */
val playtime = plans[i-1][2]
val time = calculateMinuteDifference(plans[i-1][1], plans[i][1])
var during = playtime.toInt() - time
if (during > 0) { /* 2. 만약 과제가 끝나지 않았다면 */
// 중단 작업 배열 첫번째에 남은 과제 시간을 넣는다.
ing.add(0, arrayOf(plans[i-1][0], plans[i-1][1], "$during"))
// 마지막 인덱스인데 작업이 끝나지 않았다면 제일 하단 분기를 타야한다.
if (i != plans.lastIndex) continue
} else if (during < 0) { /* 3. 만약 과제가 끝나고 시간이 남았다면 */
// 우선 끝난 과제는 정답 배열에 넣는다.
answer.add(plans[i-1][0])
while (true) {
// 중단과제 배열이 없는 경우 반복문을 종료한다.
if (ing.size == 0) break
// 남은 시간과 과제 시간을 비교한다.
val ingPlaytime = ing[0][2]
val ingDuring = ingPlaytime.toInt() + during
if (ingDuring > 0) {
// 중단 과제 시간이 남았으면 해당 작업 시간을 변경하고 중단한다.
ing[0][2] = "$ingDuring"
break
} else {
// 중단 과제가 마무리됐으면 정답 배열에 넣고 다음 과제를 이어서 한다.
during = ingDuring
answer.add(ing[0][0])
ing.removeAt(0)
}
}
} else { /* 4. 만약 과제가 제 시간에 끝났다면 */
answer.add(plans[i-1][0]) // 정답 배열에 넣는다.
}
/* 5. 현재 마지막 인덱스라면 앞 인덱스를 기준으로 계산했기 때문에 마지막 과제 예외처리 */
if (i == plans.lastIndex) {
// 마지막 과제를 정답 배열에 넣고
// 중단된 과제를 차례로 정답 배열에 넣는다.
answer.add(plans[i][0])
ing.forEach { answer.add(it[0]) }
}
}
return answer.toTypedArray()
}
fun calculateMinuteDifference(time1: String, time2: String): Int {
val (hour1, minute1) = time1.split(":").map { it.toInt() }
val (hour2, minute2) = time2.split(":").map { it.toInt() }
val totalMinute1 = hour1 * 60 + minute1
val totalMinute2 = hour2 * 60 + minute2
return if (totalMinute1 > totalMinute2) {
totalMinute1 - totalMinute2
} else {
totalMinute2 - totalMinute1
}
}
}
- 다음 과제 시작 시간과 현재 과제 시작시간의 차이를 playtime과 비교한다.
- 만약 과제가 끝나지 않았다면
- 중단 작업 배열 첫번째에 남은 과제 시간을 넣는다.
- 마지막 인덱스인데 작업이 끝나지 않았다면 제일 하단 분기를 타야한다.
- 만약 과제가 끝나고 시간이 남았다면
- 우선 끝난 과제는 정답 배열에 넣는다.
- 중단과제 배열이 없는 경우 반복문을 종료한다.
- 남은 시간과 과제 시간을 비교한다.
- 중단 과제 시간이 남았으면 해당 작업 시간을 변경하고 중단한다.
- 중단 과제가 마무리됐으면 정답 배열에 넣고 다음 과제를 이어서 한다.
- 만약 과제가 제 시간에 끝났다면
- 정답 배열에 넣는다.
- 현재 마지막 인덱스라면 앞 인덱스를 기준으로 계산했기 때문에 마지막 과제 예외처리를 해준다.
- 마지막 과제를 정답 배열에 넣고 중단된 과제를 차례로 정답 배열에 넣는다.
풀면서 발생했던 문제점 1
ing에 값이 없는 상태에서 while문이 실행되어 런타임 에러가 발생했다.
ing 배열에 값이 있는 상태에서만 while문이 실행되도록 수정하였다.
풀면서 발생했던 문제점 2
plans를 기준으로 for문을 돌면서 마지막 index인 경우 예외처리를 제대로 해주지 않았다.
처음 if (during > 0) 부분에서 그냥 continue를 시켜버려, plans의 [last-1] 값이 끝나지 않은 경우,
해당 과제를 최종적으로 수행하지 못했다고 인식하는 이슈가 발생했다.
결국 lastIndex가 아닌 경우에만 continue를 시키고, lastIndex인 경우 제일 하단 예외처리를 타도록 수정했다.
Comment
나름 재밌었던 문제이다. 접근이 쉬워서 금방 풀었다.
대신 예외처리에서 애를 먹어 테스트케이스가 없었으면 힘들었을 것 같다.
좀 더 꼼꼼하게 생각하는 연습을 해야겠다.
'프로그래머스 > Kotlin | Level2' 카테고리의 다른 글
[프로그래머스/Kotlin]Lv2 - 연속된 부분 수열의 합 (0) | 2024.06.09 |
---|---|
[프로그래머스/Kotlin]Lv2 - N-Queen (1) | 2024.06.06 |
[프로그래머스/Kotlin]Lv2 - 마법의 엘리베이터 (0) | 2024.03.21 |
[프로그래머스/Kotlin]Lv2 - 요격 시스템 (0) | 2023.10.13 |
[프로그래머스/Kotlin]Level2 - 풍선 터트리기 (0) | 2023.02.25 |