mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-09 02:53:31 +08:00
0332.重新安排行程:优化排版,补充Swift版本
This commit is contained in:
@ -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>
|
||||
|
Reference in New Issue
Block a user