📍 공원 산책
{공원의 좌표: 해당 좌표의 표시}
형식의 Map을 생성한다.N: (-1, 0) S: (+1, 0) W: (0, -1) E: (0, +1)
이다.class Solution {
fun solution(park: Array<String>, routes: Array<String>): IntArray {
var (x, y) = Pair(0, 0)
var pMap = (0..park.size-1).flatMap { i ->
(0..park[0].length-1).map { j ->
if (park[i][j] == 'S') {
x = i
y = j
}
Pair("$i$j", park[i][j])
}
}.associate { it.first to it.second }
routes.map {
var (op, n) = it.split(" ")
var (moveX, moveY) = Pair(x, y)
var isReset = false
for (i in 1..n.toInt()) {
when (op) {
"N" -> moveX -= 1
"S" -> moveX += 1
"W" -> moveY -= 1
else -> moveY += 1
}
if (!pMap.containsKey("$moveX$moveY") || pMap["$moveX$moveY"] == 'X') {
isReset = true
break
}
}
// isReset이 아닌 경우에만 이동한 경로를 반영한다.
if (!isReset) {
x = moveX
y = moveY
}
}
return intArrayOf(x, y)
}
}
어제 스리슬쩍 배워온 associate를 사용해보았다! 그러나 코드는 밑도끝도없이 길다..
위에서 작성한 풀이는 10번과 16번에서 실패를 했다. 아니 시간 초과도 아니고, 런타임 에러도 아닌데 다른 문제는 다 맞춰놓고서 도대체 왜 실패를 했는지 도저히 알 수가 없었다. 그러던 중, 질문하기 게시판에서 구세주를 만나게 된다.
세상에 좌표가 두자리 수 일때를 생각하지 못했었던 것이었다! 진짜 아뿔싸.. 덕분에 문제점을 알게되었고, 냅다 좌표 사이에 공백을 집어넣어 풀이했다.
class Solution {
fun solution(park: Array<String>, routes: Array<String>): IntArray {
var (x, y) = Pair(0, 0)
var pMap = (0..park.size-1).flatMap { i ->
(0..park[0].length-1).map { j ->
if (park[i][j] == 'S') {
x = i
y = j
}
Pair("$i $j", park[i][j])
}
}.associate { it.first to it.second }
routes.map {
var (op, n) = it.split(" ")
var (moveX, moveY) = Pair(x, y)
var isReset = false
for (i in 1..n.toInt()) {
when (op) {
"N" -> moveX -= 1
"S" -> moveX += 1
"W" -> moveY -= 1
else -> moveY += 1
}
if (!pMap.containsKey("$moveX $moveY") || pMap["$moveX $moveY"] == 'X') {
isReset = true
break
}
}
if (!isReset) {
x = moveX
y = moveY
}
}
return intArrayOf(x, y)
}
}
드디어 성공했다. 코드를 보면 map 안에 for 문 안에 when에다가 if 문도 여러 개 있고 아무튼 정신이 좀 사나운 것 같이 느껴진다. 조금 정리된 코드로 개선해보고 싶었다.
가져온 풀이는 시작 지점을 따로 함수로 빼서 풀이했다. 또 when이나 if를 사용해 좌표 이동 값을 구하는 게 아니라, Map을 만들어서 해당하는 좌표를 찾는 방식으로 풀이했다. 이 방식이 내가 풀이한 방식보다 더 좋아보였다.
그리고!! repeat이라는 인라인 반복문이 있다는 것을 알게되었다. 매번 forEach나 map을 사용했었는데 이런 것도 있었구나라는 걸 새로 알아간다.
map을 사용했을 때 return이나 break 같은 흐름 제어 키워드를 못 쓰는 줄 알았는데, @
를 사용하면 가능하다! map 뿐만 아니라 다른 고차 함수들에도 @
를 사용한 레이블을 붙여주면 흐름제어가 가능하다고 한다. 이건 정말 자주 쓰게될 것 같다.
class Solution {
private fun findStart(park: Array<String>): MutableList<Int> {
for (i in park.indices)
for (j in park[i].indices)
if (park[i][j] == 'S')
return mutableListOf(i, j)
return mutableListOf(0, 0)
}
fun solution(park: Array<String>, routes: Array<String>): IntArray {
val directions = mapOf('E' to (0 to 1), 'W' to (0 to -1), 'N' to (-1 to 0), 'S' to (1 to 0))
return routes.map { it[0] to it.drop(2).toInt() }
.fold(findStart(park)) { pos, (direction, distance) ->
val prevPos = pos.toMutableList()
val nextPos = pos.toMutableList()
repeat(distance) {
nextPos[0] += directions[direction]!!.first
nextPos[1] += directions[direction]!!.second
if (!(0 <= nextPos[0] && nextPos[0] < park.size && 0 <= nextPos[1] && nextPos[1] < park[0].length && park[nextPos[0]][nextPos[1]] != 'X'))
return@fold prevPos
}
return@fold nextPos
}.toIntArray()
}
}
문제는 어려웠지만 다른 사람 풀이에서 새로 알게된 것이 많아 보람찬 시간이었다. 알게된 걸 응용을 해야하는데, 부디 까먹지 말고 사용할 수 있기를 바란다.
그리고 첫 번째 풀이에서의 문제점을 발견하신 분.. 적게 일하고 많이 버시길 바래요. 없었으면 몇 분을 끙끙 앓았을 지 몰라요.