From a8f8f21ba93cbd6640767243b2c89350795d9303 Mon Sep 17 00:00:00 2001 From: bqlin Date: Fri, 17 Dec 2021 13:47:27 +0800 Subject: [PATCH] =?UTF-8?q?0332.=E9=87=8D=E6=96=B0=E5=AE=89=E6=8E=92?= =?UTF-8?q?=E8=A1=8C=E7=A8=8B=EF=BC=9A=E4=BC=98=E5=8C=96=E6=8E=92=E7=89=88?= =?UTF-8?q?=EF=BC=8C=E8=A1=A5=E5=85=85Swift=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0332.重新安排行程.md | 133 ++++++++++++++++++++++++++-- 1 file changed, 128 insertions(+), 5 deletions(-) diff --git a/problems/0332.重新安排行程.md b/problems/0332.重新安排行程.md index cfdea237..b5c3ca00 100644 --- a/problems/0332.重新安排行程.md +++ b/problems/0332.重新安排行程.md @@ -125,7 +125,7 @@ void backtracking(参数) { 代码如下: -``` +```cpp // unordered_map<出发机场, map<到达机场, 航班次数>> targets unordered_map> targets; bool backtracking(int ticketNum, vector& result) { @@ -142,7 +142,8 @@ bool backtracking(int ticketNum, vector& result) { 所以找到了这个叶子节点了直接返回,这个递归函数的返回值问题我们在讲解二叉树的系列的时候,在这篇[二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://programmercarl.com/0112.路径总和.html)详细介绍过。 当然本题的targets和result都需要初始化,代码如下: -``` + +```cpp for (const vector& vec : tickets) { targets[vec[0]][vec[1]]++; // 记录映射关系 } @@ -157,7 +158,7 @@ result.push_back("JFK"); // 起始机场 代码如下: -``` +```cpp if (result.size() == ticketNum + 1) { return true; } @@ -230,13 +231,15 @@ public: 一波分析之后,可以看出我就是按照回溯算法的模板来的。 代码中 -``` + +```cpp for (pair& target : targets[result[result.size() - 1]]) ``` pair里要有const,因为map中的key是不可修改的,所以是`pair`。 如果不加const,也可以复制一份pair,例如这么写: -``` + +```cpp for (pairtarget : targets[result[result.size() - 1]]) ``` @@ -445,5 +448,125 @@ var findItinerary = function(tickets) { ``` +### Swift + +直接迭代tickets数组: + +```swift +func findItinerary(_ tickets: [[String]]) -> [String] { + // 先对路线进行排序 + let tickets = tickets.sorted { (arr1, arr2) -> Bool in + if arr1[0] < arr2[0] { + return true + } else if arr1[0] > arr2[0] { + return false + } + if arr1[1] < arr2[1] { + return true + } else if arr1[1] > arr2[1] { + return false + } + return true + } + var path = ["JFK"] + var used = [Bool](repeating: false, count: tickets.count) + + @discardableResult + func backtracking() -> Bool { + // 结束条件:满足一条路径的数量 + if path.count == tickets.count + 1 { return true } + + for i in 0 ..< tickets.count { + // 巧妙之处!跳过处理过或出发站不是path末尾站的线路,即筛选出未处理的又可以衔接path的线路 + guard !used[i], tickets[i][0] == path.last! else { continue } + // 处理 + used[i] = true + path.append(tickets[i][1]) + // 递归 + if backtracking() { return true } + // 回溯 + path.removeLast() + used[i] = false + } + return false + } + backtracking() + return path +} +``` + +使用字典优化迭代遍历: + +```swift +func findItinerary(_ tickets: [[String]]) -> [String] { + // 建立出发站和目的站的一对多关系,要对目的地进行排序 + typealias Destination = (name: String, used: Bool) + var targets = [String: [Destination]]() + for line in tickets { + let src = line[0], des = line[1] + var value = targets[src] ?? [] + value.append((des, false)) + targets[src] = value + } + for (k, v) in targets { + targets[k] = v.sorted { $0.name < $1.name } + } + + var path = ["JFK"] + let pathCount = tickets.count + 1 + @discardableResult + func backtracking() -> Bool { + if path.count == pathCount { return true } + + let startPoint = path.last! + guard let end = targets[startPoint]?.count, end > 0 else { return false } + for i in 0 ..< end { + // 排除处理过的线路 + guard !targets[startPoint]![i].used else { continue } + // 处理 + targets[startPoint]![i].used = true + path.append(targets[startPoint]![i].name) + // 递归 + if backtracking() { return true } + // 回溯 + path.removeLast() + targets[startPoint]![i].used = false + } + return false + } + backtracking() + return path +} +``` + +使用插入时排序优化targets字典的构造: + +```swift +// 建立出发站和目的站的一对多关系,在构建的时候进行插入排序 +typealias Destination = (name: String, used: Bool) +var targets = [String: [Destination]]() +func sortedInsert(_ element: Destination, to array: inout [Destination]) { + var left = 0, right = array.count - 1 + while left <= right { + let mid = left + (right - left) / 2 + if array[mid].name < element.name { + left = mid + 1 + } else if array[mid].name > element.name { + right = mid - 1 + } else { + left = mid + break + } + } + array.insert(element, at: left) +} +for line in tickets { + let src = line[0], des = line[1] + var value = targets[src] ?? [] + sortedInsert((des, false), to: &value) + targets[src] = value +} +``` + -----------------------