[Kotlin] 프로그래머스 - 공원 산책

Kotlin |

Language : KO,EN

문제

링크

지나다니는 길을 'O', 장애물을 'X'로 나타낸 직사각형 격자 모양의 공원에서 로봇 강아지가 산책을 하려합니다. 산책은 로봇 강아지에 미리 입력된 명령에 따라 진행하며, 명령은 다음과 같은 형식으로 주어집니다.

  • ["방향 거리", "방향 거리" … ]

예를 들어 "E 5"는 로봇 강아지가 현재 위치에서 동쪽으로 5칸 이동했다는 의미입니다. 로봇 강아지는 명령을 수행하기 전에 다음 두 가지를 먼저 확인합니다.

  • 주어진 방향으로 이동할 때 공원을 벗어나는지 확인합니다.
  • 주어진 방향으로 이동 중 장애물을 만나는지 확인합니다.

위 두 가지중 어느 하나라도 해당된다면, 로봇 강아지는 해당 명령을 무시하고 다음 명령을 수행합니다.

공원의 가로 길이가 W, 세로 길이가 H라고 할 때, 공원의 좌측 상단의 좌표는 (0, 0), 우측 하단의 좌표는 (H - 1, W - 1) 입니다.

공원을 나타내는 문자열 배열 park, 로봇 강아지가 수행할 명령이 담긴 문자열 배열 routes가 매개변수로 주어질 때, 로봇 강아지가 모든 명령을 수행 후 놓인 위치를 [세로 방향 좌표, 가로 방향 좌표] 순으로 배열에 담아 return 하도록 solution 함수를 완성해주세요.

제한사항

park

  • park[i]는 다음 문자들로 이루어져 있으며 시작지점은 하나만 주어집니다.
  • S : 시작 지점
  • O : 이동 가능한 통로
  • X : 장애물
  • 직사각형 모양입니다.

routes

  • 첫 번째 원소부터 순서대로 명령을 수행합니다.
  • routes의 원소는 "op n"과 같은 구조로 이루어져 있으며, op는 이동할 방향, n은 이동할 칸의 수를 의미합니다.
  • op 이동할 방향
  • N : 북쪽으로 주어진 칸만큼 이동합니다.
  • S : 남쪽으로 주어진 칸만큼 이동합니다.
  • W : 서쪽으로 주어진 칸만큼 이동합니다.
  • E : 동쪽으로 주어진 칸만큼 이동합니다.

입출력 예시

입출력 예 #1

  • 입력
  • park: ["SOO","OOO","OOO"]
  • routes:  ["E 2","S 2","W 1"]
  • 출력: [2,1]

입출력 예 #2

  • 입력
  • park: ["SOO","OXX","OOO"]
  • routes: ["E 2","S 2","W 1"]
  • 출력: [0,1]

입출력 예 #3

  • 입력
  • park: ["OSO","OOO","OXO","OOO"]
  • routes: ["E 2","S 3","W 1"]
  • 출력: [0,0]

코드 1. 바둑판 그리기

class Solution {
    companion object {
        private const val START = 'S'
        private const val BLOCK = 'X'
        private const val ROAD = 'O'
    }
    
    fun solution(park: Array<String>, routes: Array<String>): IntArray {
        // 로봇 위치
        var robot = Pair(0, 0)

        // 공원 바둑판 그리기
        val row = park.first().length
        val col = park.count()
        val board = Array(row) { Array(col) { ROAD } }
        park.forEachIndexed { y, str ->
            for (x in str.indices) {
                board[x][y] = str[x]
                if (str[x] == START) robot = Pair(x, y)
            }
        }

        // 로봇 강아지 이동
        routes.forEach { route ->
            var nextX = robot.first
            var nextY = robot.second
            val (direction, distance) = route.split(" ")
            when (direction) {
                "E" -> nextX += distance.toInt() * 1
                "W" -> nextX += distance.toInt() * -1
                "N" -> nextY += distance.toInt() * -1
                "S" -> nextY += distance.toInt() * 1
            }

            // 장외
            if (nextX < 0 || nextY < 0) return@forEach
            if (nextX >= row || nextY >= col) return@forEach
            // 가는 길 장애물
            for (i in minOf(robot.first, nextX)..maxOf(robot.first, nextX)) {
                for (j in minOf(robot.second, nextY)..maxOf(robot.second, nextY)) {
                    if (board[i][j] == BLOCK) return@forEach
                }
            }
            // 이동
            robot = Pair(nextX, nextY)
        }

        return intArrayOf(robot.second, robot.first)
    }
}
테스트 1 〉	통과 (32.82ms, 63.3MB)
테스트 2 〉	통과 (21.73ms, 63.4MB)
테스트 3 〉	통과 (21.69ms, 63.8MB)
테스트 4 〉	통과 (29.60ms, 64MB)
테스트 5 〉	통과 (26.18ms, 64.4MB)
테스트 6 〉	통과 (32.12ms, 64.8MB)
테스트 7 〉	통과 (22.05ms, 64.1MB)
테스트 8 〉	통과 (22.59ms, 64.2MB)
테스트 9 〉	통과 (32.01ms, 64.2MB)
테스트 10 〉	통과 (21.94ms, 64.3MB)
테스트 11 〉	통과 (25.77ms, 64.6MB)
테스트 12 〉	통과 (32.53ms, 64.3MB)
테스트 13 〉	통과 (22.58ms, 64.2MB)
테스트 14 〉	통과 (24.18ms, 64.1MB)
테스트 15 〉	통과 (21.78ms, 64.6MB)
테스트 16 〉	통과 (23.61ms, 64.3MB)
테스트 17 〉	통과 (21.59ms, 64.1MB)
테스트 18 〉	통과 (27.57ms, 63.9MB)
테스트 19 〉	통과 (22.33ms, 63.9MB)
테스트 20 〉	통과 (22.08ms, 64.1MB)

코드 2. 바둑판 그리지 않기

class Solution {
    fun solution(park: Array<String>, routes: Array<String>): IntArray {
        var answer = intArrayOf(0, 0)
        // 이동 칸
        val directionMove = hashMapOf(
            "E" to intArrayOf(0, 1),
            "W" to intArrayOf(0, -1),
            "S" to intArrayOf(1, 0),
            "N" to intArrayOf(-1, 0)
        )

        // 초기 위치
        // forEach, forEachIndex는 반복적인 람다 호출로 퍼포먼스가 저하될 수 있기 때문에 for문 사용
        for (y in park.indices) {
            for (x in park[y].indices) {
                if (park[y][x] == 'S') answer = intArrayOf(y, x)
            }
        }

        // 이동
        routes.forEach { route ->
            val (direction, distance) = route.split(" ")
            val move = directionMove[direction]!!
            val step = distance.toInt()

            var y = answer[0]
            var x = answer[1]
            for (i in 0 until step) {
                y += move[0]
                x += move[1]

                // park.first() 보다 park[0]가 속도가 빠르다.
                if (y < 0 || x < 0 || x >= park[0].length || y >= park.size || park[y][x] == 'X') {
                    y = answer[0]
                    x = answer[1]
                    break
                }
            }
            answer = intArrayOf(y, x)
        }
        return answer
    }
}
테스트 1 〉	통과 (12.59ms, 61.6MB)
테스트 2 〉	통과 (9.49ms, 60.9MB)
테스트 3 〉	통과 (10.07ms, 61.7MB)
테스트 4 〉	통과 (10.52ms, 59.9MB)
테스트 5 〉	통과 (9.65ms, 61.7MB)
테스트 6 〉	통과 (10.82ms, 61.3MB)
테스트 7 〉	통과 (14.11ms, 60.4MB)
테스트 8 〉	통과 (10.55ms, 60.7MB)
테스트 9 〉	통과 (12.02ms, 61.4MB)
테스트 10 〉	통과 (14.19ms, 61MB)
테스트 11 〉	통과 (14.31ms, 61.4MB)
테스트 12 〉	통과 (9.11ms, 61.3MB)
테스트 13 〉	통과 (14.19ms, 62.1MB)
테스트 14 〉	통과 (14.02ms, 61.8MB)
테스트 15 〉	통과 (9.50ms, 61.4MB)
테스트 16 〉	통과 (11.62ms, 61.4MB)
테스트 17 〉	통과 (10.33ms, 60.9MB)
테스트 18 〉	통과 (10.75ms, 60.6MB)
테스트 19 〉	통과 (10.01ms, 61.1MB)
테스트 20 〉	통과 (11.82ms, 61.2MB)

민갤

Back-End Developer

백엔드 개발자입니다.