Computer Science/Algorithm

[프로그래머스] 미로 탈출 (Swift)

kyxxn 2024. 3. 17. 03:03
728x90

문제 이해

: 출발지를 찾고, 레버를 활성화 시킨 뒤 탈출을 해야 한다.
문제에서 최소 시간을 요구 했으므로 BFS를 사용할 거다.
출발지 -> 레버 찾는데 BFS 1회 동작,
레버 -> 도착지 찾는데 BFS 1회 동작으로 총 2회 BFS를 진행한다.

주요 로직

: Swift에서 문자열 파싱은 아직도 어렵다.
입출력은 다음과 같이 문자열들의 배열이 나온다.
["SOOOL","XXXXO","OOOOO","OXXXX","OOOOE"]
Swift에서 문자열에 인덱스 접근이 불가능하기도 하고, separator도 없기 때문에 enumerated 메소드를 사용할 거다.

Swift Enumerated

enumerated() 메소드는 Array 내의 함수로, (n, x)로 이루어진 쌍의 튜플을 반환한다.
n은 0에서 시작하는 연속된 정수를 나타내고, x는 원소를 갖게 된다.


maps에 담긴 ["SOOOL","XXXXO","OOOOO","OXXXX","OOOOE"] 문자열을 (0, "SOOOL"), (1, "XXXXO"), (2, "OOOOO"), (3, "OXXXX"), (4, "OOOOE")와 같이 반환해준다.
이후, 한 번더 enumerated()를 해주어 문자열의 배열을 문자 2차원 배열로 만들어준다.
왜냐하면 Swift에서 String은 인덱스적 접근이 안되기 때문 (maps[0][1] 이런식으로 X)
mapParsing 배열에 Array(map)을 하여 ['S', 'O', 'O', 'O', 'L']로 문자 2차원 배열을 형성해준다.

distance 배열 사용

visited 배열을 사용하지 않고, distance 배열을 사용하여 "시작 지점으로부터 걸린 거리 + 기존 visited 배열의 역할"을 하게 한다.
distance 배열을 다 -1로 초기화 해주고, distance[nextX][nextY] = distance[curX][curY] + 1로 해주었음
이후 End 지점에서 distance[nextX][nextY]를 반환하면 최소 시간을 반환하게 된다.

BFS 함수에서 Nil 반환 & guard let 문법 사용


guard let 구문으로 정상적으로 end를 찾았을 경우 distance 배열의 마지막 end 지점의 최소 시간이 반환된다.
그러나 찾지 못 하고 queue가 빈 상태가 되면 BFS 함수의 마지막 "return nil"을 맞이하여 -1을 최종적으로 반환하게 된다.
출발지 -> 레버와 레버 -> 도착지 중 한 번이라도 nil을 만나면 -1을 반환하게 된다.

// 00:52 시작
// 01:52 끝
// 레버를 당겨야만 미로를 빠져나갈 수 있음
// 시작 -> 레버 찾기 BFS
// 레버 -> 출구 찾기 BFS
import Foundation

func solution(_ maps:[String]) -> Int {
    let dx = [-1,1,0,0], dy = [0,0,-1,1]
    var start: (Int, Int) = (0, 0)
    var lever: (Int, Int) = (0, 0)
    var end: (Int, Int) = (0, 0)
    var mapParsing: [[Character]] = []

    // 시작지점 및 레버찾기
    for (i, map) in maps.enumerated() {
        for (k, l) in map.enumerated() {
            if l == "S" {
                start = (i, k)
            }else if l == "L" {
                lever = (i, k)
            }else if l == "E" {
                end = (i, k)
            }
        }
        mapParsing.append(Array(map))
    }

    func bfs(first: (Int, Int), last: (Int, Int)) -> Int? {
        var distance = Array(repeating: Array(repeating: -1, count: maps[0].count), count: maps.count)
        var queue: [(Int, Int)] = [first]
        distance[first.0][first.1] = 0

        while !queue.isEmpty {
            let cur: (Int, Int) = queue.removeFirst()
            let curX = cur.0, curY = cur.1

            for i in 0..<4 {
                let nx = curX + dx[i], ny = curY + dy[i]
                let maxX = maps.count, maxY = maps[0].count
                if nx < maxX && nx >= 0 && ny >= 0 && ny < maxY {
                    if mapParsing[nx][ny] != "X" && distance[nx][ny] == -1{
                        queue.append((nx, ny))
                        distance[nx][ny] = distance[curX][curY] + 1
                        if (nx, ny) == last {
                            return distance[nx][ny]
                        }
                    }
                }
            }
        }

        return nil
    }

    guard let startToLeverTime: Int = bfs(first: start, last: lever) else {return -1}
    guard let leverToEndTime: Int = bfs(first: lever, last: end) else {return -1}

    return startToLeverTime + leverToEndTime
}

 


 

Reference
https://developer.apple.com/documentation/swift/array/enumerated()

 

enumerated() | Apple Developer Documentation

Returns a sequence of pairs (n, x), where n represents a consecutive integer starting at zero and x represents an element of the sequence.

developer.apple.com