실수를 유발하게 하는 포인트가 몇가지 있다. 우선 문제에 동생과 수빈이가 위치한 좌표만 적혀있을 뿐 어디까지 이동이 가능한지 제약이 적혀있지 않다. 즉 동생의 좌표 최댓값 100000보다 더 큰 범위로 순간이동 후 걸어와서 발견하는 방법이 존재한다는 것이다. 역으로 돌아오는 것은 걸어오는 방법(-1) 밖에 없기에 최대 유효 범위는 100001이다. 그보다 큰 위치에서 돌아오는 방법은 최소 시간을 갱신할 수 없다. 따라서 100002개의 배열을 생성한 뒤 한 칸 후퇴, 한 칸 전진, 두배 순간이동의 방법으로 너비 우선 탐색을 수행하면 된다.
다음으로 중요한 부분은 같은 시간이 걸리더라도 걸어가서 동생을 마주하는 방법과 순간이동으로 마주하는 방법은 다르게 계산해야한다는 점이다. 따라서 도달하게 된 시간이 같다면 도달 방법 수 갱신만 하지 말고 다음 탐색 큐에 담아주어야 한다.
마지막으로 이동하지 않는 것도 방법으로 세야 한다는 것이다. 즉 처음부터 동생과 수빈이의 위치가 같은 경우라면 1을 반환해야 한다.
투 포인터 문제다. 예전에 런타임 에러를 마주하고 해결하지 못해 포기했다가 최근에 다시 봐서 해결한 문제.
풀이
입력된 레고를 길이 순으로 정렬한 뒤 처음과 끝에서 탐색하면서 범위를 좁히면 된다. 탐색 도중 조건이 맞으면 바로 결과를 출력. 대신 테스트 케이스의 제한이 안 적혀있어 결과물을 모아서 한 번에 출력했다. 스위프트의 print() 메서드가 다른 언어에 비해 속도가 느리기 때문에 출력 양이 많은 경우에는 이런 식으로 해결하는 경우가 많다.
정답 코드
주석처리 부분이 런타임에러 코드의 수정 전 부분이다. 무한 입력을 받기 위해 while let 문을 사용했는데, 마지막 입력없이 끝나는 부분에서 공백 문자열에 대해 정수형 변환이 일어나 런타임 에러가 일어나지 않았나 생각해본다. xcode에서는 아무 문제없이 빌드되길래 다른 케이스에서 인덱스 오류인 줄 알고 여러 번 삽질했다..
An interface to the user’s defaults database, where you store key-value pairs persistently across launches of your app.
유저디폴트, 사용자 기본값이라고 생각하면 된다. 키-값 형태로 저장되며 키는 문자열형태, 값은 스위프트의 기본자료형인 Float, Double, Int, Bool, URL 타입 이외에 NSData,, NSString,, NSNumber,, NSDate,, NSArray,,NSDictionary 자료형을 담아낼 수 있다고한다.
설명만 들었을때는 이걸 어떻게 사용하는건가 싶었는데, Zedd님의 글을 보고서 금방 이해했다. 앱의 최근 상태를 저장하거나 최근 값을 불러내기 위해 사용된다고 보면된다.
간단하게 NavigationView를 만들어서 확인해보았다. 좌측이 UserDefaults를 사용하지 않은 경우, 뷰가 생성될 때마다 초기값으로 시작하는 것을 볼 수 있는 반면, UserDefaults를 사용하게 되면 값들을 따로 저장하고 불러오는 것이 가능해진다. 저장된 자료들은 앱을 껐다 켜도 그대로 남아있는 모습을 볼 수 있었다.
NextView의 onAppear, onDisappear 구현을 통해 UserDefaults를 저장하고 불러오는 동작을 구현하였다.
Persist or cache data on a single device, or sync data to multiple devices with CloudKit.
UserDefaults의 경우는 간단한 유저 설정을 저장하는 데에 용이하지만, 더 복잡한 사용자 자료를 담아내려면 Coredata가 적합하다.
coredata에는 많은 기능들이 있지만 대다수가 Persistence 기능을 위해 사용하는 것으로 알고 있다.
Persistence
Core Data abstracts the details of mapping your objects to a store, making it easy to save data from Swift and Objective-C without administering a database directly.
문서에 따르면 데이터베이스를 직접 사용하지 않고 swift, obj-c 자료들을 손쉽게 저장할 수 있다고 한다. zedd님의 설명을 읽어보니 대략적인 느낌은 알겠으나 아직 본인의 역량이 부족한지 완벽하게 이해가 되지 않는다. coredata 부분을 완벽하게 이해하기 위해서는 나중에 더 많은 시간을 들여 공부해야겠다.
출발 노선 지점에서 각 지점으로의 최소비용을 담을 dist:[Int]() 배열을 생성한다. 이후 입력되는 노선의 정보를 저장한 후 너비 우선 탐색을 통해 다음 노선까지의 비용이 더 저렴하다면 dist 원소 값을 경신한 후 값이 경신된 해당 지점을 큐에 담아 다음 탐색 경로에 추가해주면서 탐색을 수행하면 된다.
참고해야 할 점은 입력받은 노선 정보를 비용 기준 오름차순 정렬해주어야 한다는 점이다. 다익스트라 알고리즘의 조건인 최소비용부터 탐색한다는 조건을 생각하지 못해 정렬하지 않은 채로 제출했었는데 시간 초과가 일어났었다. 곰곰이 생각해보니 A -> B로 가는 노선이 여러 개일 경우 정렬을 하지 않은 채로 탐색을 수행한다면 큐에 중복된 경로를 추가하게 되어 불필요한 탐색을 수행하게 된다.