
미로 탈출 명령어 - Swift 문제풀이
문제 링크
카카오 코딩테스트: 미로 탈출 명령어
문제 분석
미로 탈출 조건
- 격자 바깥으로 나갈 수 없다.
- (x, y)부터 (r, c) 까지 이동거리가 k여야 한다.
- 같은 격자를 두 번 이상 방문해도 된다.
- 탈출 경로(문자열)가 사전 순으로 가장 빠른 경로로 탈출해야 한다.예를들어 탈출 경로가 (lldud, dllrl) 가 있으면, dllrl 가 정답이다.
- 만약 탈출할 수 없는 경우 “impossible” 를 출력한다.
내 코드
가장 직관적인 방법
- 사전 순으로 가장 빠른 방향부터 선택하도록 dx, dy를 놓고
- 이동 횟수가 k가 되면 return (이 때까지의 커멘드를 정답 후보에 넣는다.)
- 모든 탐색을 마친 뒤 정답 후보에서 사전순으로 가장 빠른 문자열을 고른다.
import Foundation
func solution(_ n:Int, _ m:Int, _ x:Int, _ y:Int, _ r:Int, _ c:Int, _ k:Int) -> String {
// d, l, r, u
let dx = [1, 0, 0, -1] // 아래, 왼쪽, 오른쪽, 위
let dy = [0, -1, 1, 0]
let directions = ["d", "l", "r", "u"]
var ret: [String] = []
func go(_ x: Int, _ y: Int, _ dist: Int, _ a: String) {
if dist == k {
if x == r && y == c {
ret.append(a)
}
return
}
for i in 0..<4 {
let nx = x + dx[i]
let ny = y + dy[i]
if nx < 1 || nx > n || ny < 1 || ny > m { continue }
go(nx, ny, dist + 1, a + directions[i])
}
}
go(x, y, 0, "")
if ret.isEmpty {
return "impossible"
}
return ret.sorted().first!
}그러나 이 코드는 모든 방향 (4 방향)을 최대 k번 탐색하는 것을 반복해야 한다. 따라서 시간 복잡도는 O(4^k) 이며, k는 2,500 으로 시간초과가 날 수 있다.
따라서, 이 코드까지 작성 오기 전에 미리 ‘아, 시간초과가 나겠구나’ 생각하고 방법은 빠르게 바꿔야 한다.
이 문제를 푸는 방법은
- 이동을 시작할 때부터 가장 빠른 문자로 이동하는 것이 무조건 좋다.
- 위치 (x, y)에서 k번 이동까지 남은 이동 횟수 remain이 정해지면, 해당 상태에서 탈출까지 최적의 경로는 하나다.
- remain = k - 현재 이동 횟수
import Foundation
func solution(_ n:Int, _ m:Int, _ x:Int, _ y:Int, _ r:Int, _ c:Int, _ k:Int) -> String {
var result = "impossible"
func go(_ x: Int, _ y: Int, _ path: String) {
// 이미 최적의 해를 찾았으므로 return
if result != "impossible" { return }
let dist = abs(x - r) + abs(y - c)
let canGo = k - path.count
if canGo < dist || (canGo - dist) % 2 == 1 { return }
if canGo == 0 && dist == 0 {
result = path
return
}
if x < n { go(x + 1, y, path + "d") }
if 1 < y { go(x, y - 1, path + "l") }
if y < m { go(x, y + 1, path + "r") }
if 1 < x { go(x - 1, y, path + "u")}
}
go(x, y, "")
return result
}배운 점
리팩토링 코드