# 基本概念

DFS和BFS的具体定义这里不做赘述。笔者谈谈自己对此的形象理解：假如你在家中发现钥匙不见了，为了找到钥匙，你有两种选择：

1. 从当前角落开始，顺着一个方向不停的找。假如这个方向全部搜索完毕依然没有找到钥匙，就回到起始角落，从另一个方向寻找，直到找到钥匙或所有方向都搜索完毕为止。这种方法就是DFS。
2. 从当前角落开始，每次把最近所有方向的角落全部搜索一遍，直到找到钥匙或所有方向都搜索完毕为止。这种方法就是BFS。

DFS的搜索步骤为

• 1
• 2 -> 3 -> 4
• 5
• 6 ->7 -> 8
• 9 -> 10

BFS的搜索步骤为

• 1
• 2 -> 5 -> 6 -> 9
• 3 -> 4
• 7
• 10
• 8

#### DFS的Swift实现：

``````func dfs(_ root: Node?) {
guard let root = root else {
return
}

visit(root)
root.visited = true

for node in root.neighbors {
if !node.visited {
dfs(node)
}
}

}
``````

#### BFS的Swift实现：

``````func bfs(_ root: Node?) {
var queue = [Node]()

if let root = root {
queue.append(root)
}

while !queue.isEmpty {
let current = queue.removeFirst()

visit(current)
current.visited = true

for node in current.neighbors {
if !node.visited {
queue.append(node)
}
}
}
}
``````

# iOS实战演练

### 第一步：实现字母矩阵

``````var xOffset = 0
var yOffset = 0
let cellWidth = UIScreen.mainScreen().bounds.size.width / matrix[0].count
let cellHeight = UIScreen.mainScreen().bounds.size.height / matrix.count

for i in 0 ..< matrix.count {
for j in 0 ..< matrix[0].count {
let label = UILabel(frame: CGRect(x: xOffset, y: yOffset, width: cellWidth, height: cellHeight))
label.text = String(matrix[i][j])
labels.append(label)
xOffset += cellWidth
}
xOffset = 0
yOffset += cellHeight
}

``````

### 第二步：用DFS实现搜索单词

``````func searchWord(_ board: [[Character]]) -> Bool {
guard board.count > 0 && board[0].count > 0 else {
return false
}

let (m, n) = (board.count, board[0].count)
var visited = Array(repeating: Array(repeating: false, count: n), count: m)
var wordContent = [Character]("crowd".characters)

for i in 0 ..< m {
for j in 0 ..< n {
if dfs(board, wordContent, m, n, i, j, &visited, 0) {
return true
}
}
}

return false
}

func dfs(_ board: [[Character]], _ wordContent: [Character], _ m: Int, _ n: Int, _ i: Int, _ j: Int, _ visited: inout [[Bool]], _ index: Int) -> Bool {
if index == wordContent.count {
return true
}

guard i >= 0 && i < m && j >= 0 && j < n else {
return false
}
guard !visited[i][j] && board[i][j] == wordContent[index] else {
return false
}

visited[i][j] = true

if dfs(board, wordContent, m, n, i + 1, j, &visited, index + 1) || dfs(board, wordContent, m, n, i - 1, j, &visited, index + 1) || dfs(board, wordContent, m, n, i, j + 1, &visited, index + 1) || dfs(board, wordContent, m, n, i, j - 1, &visited, index + 1) {
return true
}

visited[i][j] = false
return false
}

``````

### 第三步：优化算法，进阶

``````func findWords(_ board: [[Character]], _ dict: Set<String>) -> [String] {}
``````

``````func findWords(_ board: [[Character]], _ dict: Set<String>) -> [String] {
var res = [String]()

let (m, n) = (board.count, board[0].count)

let trie = _convertSetToTrie(dict)
var visited = Array(repeating: Array(repeating: false, count: n), count: m)

for i in 0 ..< m {
for j in 0 ..< n {
_dfs(board, m, n, i, j, &visited, &res, trie, "")
}
}

return res
}

private func _dfs(_ board: [[Character]], _ m: Int, _ n: Int, _ i: Int, _ j: Int, inout _ visited: [[Bool]], inout _ res: [String], _ trie: Trie, _ str: String) {
// 越界
guard i >= 0 && i < m && j >= 0 && j < n else {
return
}

// 已经访问过了
guard !visited[i][j] else {
return
}

// 搜索目前字母组合是否是单词前缀
var str = str + "\(board[i][j])"
guard trie.prefixWith(str) else {
return
}

// 确认当前字母组合是否为单词
if trie.isWord(str) && !res.contains(str) {
res.append(str)
}

// 继续搜索上下左右四个方向
visited[i][j] = true
_dfs(board, m, n, i + 1, j, &visited, &res, trie, str)
_dfs(board, m, n, i - 1, j, &visited, &res, trie, str)
_dfs(board, m, n, i, j + 1, &visited, &res, trie, str)
_dfs(board, m, n, i, j - 1, &visited, &res, trie, str)
visited[i][j] = true
}
``````