0332.重新安排行程:优化排版,补充Swift版本

This commit is contained in:
bqlin
2021-12-17 13:47:27 +08:00
parent e70a6ff0f1
commit a8f8f21ba9

View File

@ -125,7 +125,7 @@ void backtracking(参数) {
代码如下:
```
```cpp
// unordered_map<出发机场, map<到达机场, 航班次数>> targets
unordered_map<string, map<string, int>> targets;
bool backtracking(int ticketNum, vector<string>& result) {
@ -142,7 +142,8 @@ bool backtracking(int ticketNum, vector<string>& result) {
所以找到了这个叶子节点了直接返回,这个递归函数的返回值问题我们在讲解二叉树的系列的时候,在这篇[二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://programmercarl.com/0112.路径总和.html)详细介绍过。
当然本题的targets和result都需要初始化代码如下
```
```cpp
for (const vector<string>& 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<const string, int>& target : targets[result[result.size() - 1]])
```
pair里要有const因为map中的key是不可修改的所以是`pair<const string, int>`
如果不加const也可以复制一份pair例如这么写
```
```cpp
for (pair<string, int>target : 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
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>