2021 카카오 코드 테스트의 5번 문제 광고 삽입 대한 풀이입니다.
문제에 대한 설명과 풀이는 kakao Tech에서 확인할 수 있으며, 이 포스트에서는 kotlin으로 문제를 해결하는 방법을 작성하겠습니다.
입력값
- play_time:String = 동영상의 총길이를 "HH:MM:SS" 형식으로 나타낸 문자열
- adv_time:String = 광고 영상의 총길이를 "HH:MM:SS" 형식으로 나타낸 문자열
- logs:Array<String> = 시청자들의 누적 재생시간을 "HH:MM:SS-HH:MM:SS" 형식으로 나타낸 배열
출력 결과
- answer:String = 광고 영상 삽입 시 최고 누적 재생시간의 시작시간을 "HH:MM:SS" 형식으로 나타낸 문자열
설명
광고 영상을 어느 시간에 삽입해야 시청자의 누적 재생시간이 가장 많을지 계산하는 문제입니다.
우선 입력값에 대한 제약사항을 확인해보면 다음과 같습니다.
- play_time: 00시간 00분 01초 이상 99시간 59분 59초
- adv_time: 00시간 00분 01초 이상 play_time과 같거나 작다.
정답을 계산하기 위해 logs의 누적 재생시간의 각 중복되는 시간을 계산해야 합니다.
예시
4명의 시청자의 기록을 표로 그려보았습니다.
맨 위 index는 초를 의미하며, 즉 영상의 총길이는 10초를 의미합니다.
- a : 00:00:01 ~ 00:00:04
- b : 00:00:02 ~ 00:00:06
- c : 00:00:08 ~ 00:00:09
- d : 00:00:01 ~ 00:00:09
여기서 헷갈리면 안 되는 점은 재생 시간의 끝은 종료를 의미하므로, 재생시간에 포함해서는 안됩니다.
4번을 예시로 보면 a의 재생시간이 종료되므로 값에서 제외되었습니다.
이렇게 영상의 누적 재생 시간은 초 단위로 계산을 해두면 어느 시간이 가장 적게 재생되었는지, 또는 가장 많이 재생되었는지 알 수 있게 됩니다.
초 단위 변환
위의 방식대로 풀이하기 위해 입력값인 HH:MM:SS 형식을 Int 값으로 변경시킬 수 있도록 함수를 만들어줍니다.
//HH:MM:SS를 초로 변경하여 반환
fun ConvertSecond(strTime:String):Int {
val (t, m, s) = ConvertTime(strTime)
return time2Second(t, m, s)
}
//HH:MM:SS를 split하여 반환
fun ConvertTime(strTime:String):Triple<Int,Int,Int> {
val sl = strTime.split(":")
return Triple(sl[0].toInt(), sl[1].toInt(), sl[2].toInt())
}
//시, 분, 초를 초 단위로 변경
fun time2Second(time:Int, minute:Int, second:Int):Int {
return (time * 60 * 60) + (minute * 60) + (second)
}
그 후 play_time과 adv_time을 초로 변환해줍니다.
fun solution (play_time:String, adv_time:String, logs:Array<String>):String {
var answer = ""
var play_time_sec = ConvertSecond(play_time)
var adv_time_sec = ConvertSecond(adv_time)
retrun answer
}
Logs 추출
시청자들의 누적 재생시간을 계산하기 위해 logs의 요소를 초로 변환하고 이를 기록해주려 합니다.
fun solution (play_time:String, adv_time:String, logs:Array<String>):String {
var answer = ""
var play_time_sec = ConvertSecond(play_time)
var adv_time_sec = ConvertSecond(adv_time)
for( i in logs.indices) {
var splitList = logs.get(i).split("-")
var log_start_time_sec = ConvertSecond(splitList[0])
var log_end_time_end = ConvertSecond(splitList[1])
}
retrun answer
}
누적 재생 수 계산
각 시청자의 시작 재생시간과 종료 재생시간을 얻었다면, 각 시간별(초 단위)로 몇 명의 시청자가 재생하였는지 알아야 합니다.
위에서 설명한 시청자 재생 시간표와 같이 초 단위로 계산하기 위해선 초 단위로 몇 명의 시청자가 동영상을 재생 중인지에 대한 정보를 기록할 배열이 필요합니다.
배열의 크기는 동영상의 총길이 + 1 만큼 주어지면 되므로 Array<Int>(play_time_sec + 1) { 0 } 이 됩니다.
- 영상의 최대 길이는 99시간 59분 59초
- 배열의 최대 크기는 (99 * 60 * 60) + (59 * 60) + 59 = 35999입니다.
- + 1이 주어지는 건 index와 시간을 동일하게 만들기 위함입니다.
기록할 배열을 만들었다면 이제 기록을 해야 합니다.
배열에 기록될 정보는 시청자의 재생시간 ~ 종료 시간이 돼야 하므로, 시작 시간과 종료 시간의 범위에 값을 주어야겠지만, 각 log 별 시간차만큼 반복 횟수가 늘어나므로 비효율적이므로 다른 방법으로 접근하겠습니다.
- 시작 시간과 종료 시간의 index에 +1 , -1을 기록합니다.
- arr[index] = arr[index] + arr[index - 1]을 반복하여 계산합니다.
- 입력값 조건이 1초부터 이므로 index는 1부터 시작합니다.
Code
fun solution (play_time:String, adv_time:String, logs:Array<String>):String {
var answer = ""
var play_time_sec = ConvertSecond(play_time)
var adv_time_sec = ConvertSecond(adv_time)
var arrCache = Array<Int>(play_time_sec + 1) { 0 } // 입력값 조건 0이 없으므로, 값을 1증가
for( i in logs.indices) {
var splitList = logs.get(i).split("-")
var log_start_time_sec = ConvertSecond(splitList[0])
var log_end_time_end = ConvertSecond(splitList[1])
arrCache.set(log_start_time_sec, arrCache.get(log_start_time_sec) + 1)//시작 index 1삽입
arrCache.set(log_end_time_sec, arrCache.get(log_end_time_sec) - 1) // 시작 index -1 삽입
}
for(i in 1..play_time_sec) {
arrCache.set(i, arrCache.get(i) + arrCache.get(i - 1))
}
retrun answer
}
광고 삽입 위치 계산
누적 수 까지 계산이 완료되었다면 어느 위치에 광고를 두어야 효과적일지 계산되면 끝입니다!
- 누적 시간 계산을 위해 arrCahce에서 1 ~ adv_time_sec 범위만큼의 값을 합쳐 maxPlayTime과 temp 변수에 저장 및 index를 기록할 maxPlayIndex 변수를 선언합니다.
- maxPlayIndex는 광고가 삽입되기 적합한 시작시간 즉 answer입니다.
- maxPlayTime, temp, maxPlayIndex 타입은 Long으로 지정해야 문제를 통과할 수 있습니다.
- arrCache에서 adv_time_sec ~ play_time_sec 범위를 1씩 이동합니다. (index)
- 이동하며 arrCache.get(index) - arrCache.get(index - adv_time_sec)를 계산합니다.(sum_adv)
- 이를 통해 index 이동 후 누적 시간이 증가되었는지 감소되었는지 알 수 있습니다.
- sum_adv + maxPlayTime 값을 temp와 비교합니다.
- maxPlayTime 값이 클 경우 현재 누적 광고시간 값이 가장 큰 것이므로 temp에 값을 저장하고 현재 index를 ㅡmaxPlayIndex에 저장합니다.
- 1~4 과정을 반복 후 나온 maxPlayIndex를 HH:MM:SS 형식으로 변경하면 정답입니다!
Code
fun solution(play_time: String, adv_time: String, logs: Array<String>): String {
val play_time_sec = ConvertSecond(play_time)
val adv_time_sec = ConvertSecond(adv_time)
val arrCache:Array<Long> = Array<Long>(play_time_sec + 1) { 0 }
...
var maxPlayTime:Long = 0
var maxPlayIndex:Long = 0
var temp:Long = 0
// adv_time_sec 범위의 값을 계산
for(i in 1 until adv_time_sec) {
maxPlayTime += arrCache.get(i)
}
temp = maxPlayTime
//동영상의 끝은 입력값 조건 상 0이므로 계산하지 않습니다. (until)
for(i in adv_time until play_time_sec) {
maxPlayTime = maxPlayTime + arrCache.get(i) - arrCache.get(i - adv_time)
if (maxPlayTime > temp) {
temp = maxPlayTime
maxPlayIndex = i - adv_time_sec + 1
}
}
var answer = String.format("%02d:%02d:%02d", maxPlayIndex / 3600, maxPlayIndex / 60 % 60, maxPlayIndex % 60)
return answer
}
Source Code
fun solution(play_time: String, adv_time: String, logs: Array<String>): String {
val play_time_sec = ConvertSecond(play_time)
val adv_time_sec = ConvertSecond(adv_time)
var arrCache = Array<Int>(play_time_sec + 1) { 0 } // 입력값 조건 0이 없으므로, 값을 1증가
for( i in logs.indices) {
var splitList = logs.get(i).split("-")
var log_start_time_sec = ConvertSecond(splitList[0])
var log_end_time_end = ConvertSecond(splitList[1])
arrCache.set(log_start_time_sec, arrCache.get(log_start_time_sec) + 1)//시작 index 1삽입
arrCache.set(log_end_time_sec, arrCache.get(log_end_time_sec) - 1) // 시작 index -1 삽입
}
for(i in 1..play_time_sec) {
arrCache.set(i, arrCache.get(i) + arrCache.get(i - 1))
}
var maxPlayTime:Long = 0
var maxPlayIndex:Long = 0
var temp:Long = 0
// adv_time_sec 범위의 값을 계산
for(i in 1 until adv_time_sec) {
maxPlayTime += arrCache.get(i)
}
temp = maxPlayTime
//동영상의 끝은 입력값 조건 상 0이므로 계산하지 않습니다. (until)
for(i in adv_time until play_time_sec) {
maxPlayTime = maxPlayTime + arrCache.get(i) - arrCache.get(i - adv_time)
if (maxPlayTime > temp) {
temp = maxPlayTime
maxPlayIndex = i - adv_time_sec + 1
}
}
var answer = String.format("%02d:%02d:%02d", maxPlayIndex / 3600, maxPlayIndex / 60 % 60, maxPlayIndex % 60)
return answer
}
'코테' 카테고리의 다른 글
2021 카카오 코테 문제 - 순위 검색 풀이 [Kotlin] (0) | 2021.05.19 |
---|