Kotlin [프로그래머스] 달리기 경주
업데이트:
카테고리: Kotlin
/문제
얀에서는 매년 달리기 경주가 열립니다. 해설진들은 선수들이 자기 바로 앞의 선수를 추월할 때 추월한 선수의 이름을 부릅니다. 예를 들어 1등부터 3등까지 “mumu”, “soe”, “poe” 선수들이 순서대로 달리고 있을 때, 해설진이 “soe”선수를 불렀다면 2등인 “soe” 선수가 1등인 “mumu” 선수를 추월했다는 것입니다. 즉 “soe” 선수가 1등, “mumu” 선수가 2등으로 바뀝니다.
선수들의 이름이 1등부터 현재 등수 순서대로 담긴 문자열 배열 players
와 해설진이 부른 이름을 담은 문자열 배열 callings
가 매개변수로 주어질 때, 경주가 끝났을 때 선수들의 이름을 1등부터 등수 순서대로 배열에 담아 return 하는 solution 함수를 완성해주세요.
접근방법
- 심판이 이름을 부르면 추월이 발생
- 이름을 불린 선수와 앞등의 선수를 바꾼다
callings
의 배열이 끝날 때까지 반복
해결
class Solution {
fun solution(players: Array<String>, callings: Array<String>): Array<String> {
var currentPlayers = players
for (calling in callings) {
currentPlayers = changeRank(currentPlayers, calling)
}
return currentPlayers
}
fun changeRank(players: Array<String>, name: String): Array<String> {
val changePlayers = players
val rank = players.indexOf(name)
val firstPlayer = players[rank-1]
changePlayers[rank-1] = name
changePlayers[rank] = firstPlayer
return changePlayers
}
}
몇가지 문제의 타임아웃이 발생
List 구조로 진행하는 연산은 시간복잡도가 커짐
극단적으로 말해서 50000명의 선수 중 마지막에 찾아야 할 선수가 있다면 indexOf()
에 최대 50000(O(n)
)의 시간이 발생한다.
Dictionary 구조의 경우 해시 테이블로 구현되어 있기 때문에 O(1)이 시간복잡도가 걸린다.
해시 테이블은 Key, Value
로 데이터를 저장하는 자료구조 중 하나로 데이터를 빠르게 검색할 수 있음 → Key 값으로 데이터 조회를 하기 때문에 해시 함수를 한번만 실행하면 된다.
class Solution {
fun changeRank(players: MutableMap<Int, String>, name: String): MutableMap<Int, String>{
val changePlayers: MutableMap<Int, String> = players
val rank = players.filterValues{it == name}.keys
for (ran in rank) {
val first = players[ran] ?: ""
val second = players[ran-1] ?: ""
changePlayers[ran-1] = first
changePlayers[ran] = second
}
return changePlayers
}
fun solution(players: Array<String>, callings: Array<String>): ArrayList<String> {
var hashtable = mutableMapOf<Int, String>()
var rank = 1
players.map { player ->
hashtable[rank] = player
rank += 1
}
callings.map { calling ->
hashtable = changeRank(hashtable, calling)
}
return ArrayList(hashtable.values)
}
}
mutableMap으로 변환 시키는 과정을 추가하였더니 갯수가 적을 때는 확실히 빨라졌다가 결국 갯수가 많아지니 시간 초과가 뜬다. (2.xx ms → 0.9ms)
일일히 변환하는게 아닌 hashtable에 적용 players.forEachIndexed { index, s -> hastable[s] = index }
인덱스와 values로 등수와 이름을 hashtable에 넣을 수 있다.
class Solution {
fun solution(players: Array<String>, callings: Array<String>): Array<String> {
val hashtable = mutableMapOf<String, Int>()
players.forEachIndexed { index, s -> hashtable[s] = index }
callings.forEachIndexed { index, name ->
// 해쉬 테이블에는 이름과 순위를 순서 상관 없이 저장
val callRank = hashtable[name] ?: 0
// 실제 데이터 변환은 players에서 이뤄짐
val frontPlayer = players[callRank - 1]
players[callRank - 1] = name
players[callRank] = frontPlayer
hashtable[name] = callRank - 1
hashtable[frontPlayer] = callRank
}
return players
}
}