공원 산책 | 프로그래머스

김태영·2024년 6월 5일
0

코딩 테스트

목록 보기
11/33
post-thumbnail

📍 공원 산책

✅ 풀이

👆 첫 번째 풀이 (실패)

  • {공원의 좌표: 해당 좌표의 표시} 형식의 Map을 생성한다.
    • 빠르게 장애물이 있는지를 찾기 위함
    • Map을 생성하는 과정에서 시작 지점의 위치도 설정해준다.
  • 구한 시작 지점 위치에 이동 경로들을 더해준다.
    • N: (-1, 0) S: (+1, 0) W: (0, -1) E: (0, +1) 이다.
    • conainsKey로 생성한 공원 Map에 해당 좌표가 존재하는지 확인한다.
    • 이동 경로에 X 표시가 있는지 확인하기 위해 1씩 더해서 확인한다.
    • 범위를 벗어나거나 경로에 X 표시가 있으면 이동하지 않는다.
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()
    }
}

💭 후기

문제는 어려웠지만 다른 사람 풀이에서 새로 알게된 것이 많아 보람찬 시간이었다. 알게된 걸 응용을 해야하는데, 부디 까먹지 말고 사용할 수 있기를 바란다.

그리고 첫 번째 풀이에서의 문제점을 발견하신 분.. 적게 일하고 많이 버시길 바래요. 없었으면 몇 분을 끙끙 앓았을 지 몰라요.

profile
화이팅

0개의 댓글

관련 채용 정보