---
# System prepended metadata

title: 深度優先搜尋DFS
tags: [' LeetCode', 演算法]

---

---
tags: 演算法, LeetCode
disqus: HackMD
---

# 深度優先搜尋DFS

## 介紹

:::info
節點選項是用 **後進先出(LIFO)** 方式進行管理，所以可以使用堆疊的資料結構
:::

![](https://i.imgur.com/yL1sOAN.gif)

深度優先搜尋(DFS)演算法是一種遍歷圖形或樹形結構的方法，它會從起點開始遍歷，並儘可能深入每一個節點，直到找到目標節點或已經訪問過所有節點。在搜索過程中，`DFS` 會使用一個堆疊(Stack)來存儲所有還未訪問的節點。當一個節點被訪問時，它會被標記為已訪問，並將其相鄰的未訪問節點推入堆疊中，繼續遍歷直到找到目標節點或堆疊被清空。`DFS` 演算法容易實現，但可能會陷入無限循環或遍歷過多節點。

## 虛擬碼

以下是一個基本的深度優先搜尋演算法的範本:

```javascript=
function DFS(G, s) {
    const stack = [];
    stack.push(s);
    while (stack.length > 0) {
        const v = stack.pop();
        if (!G[v].visited) {
            G[v].visited = true;
            for (let u of G[v].adjacent) {
                stack.push(u);
            }
        }
    }
}

let G = {
    1: { visited: false, adjacent: [2, 3] },
    2: { visited: false, adjacent: [1, 4] },
    3: { visited: false, adjacent: [1, 4] },
    4: { visited: false, adjacent: [2, 3, 5] },
    5: { visited: false, adjacent: [4] }
};

DFS(G, 1);
```

G是一個圖形，s是起點。我們使用一個堆疊stack來存儲還未訪問的節點。
在遍歷過程中，如果一個節點v還沒有被訪問過，我們標記v為已訪問，然後將其相鄰的未訪問節點推入堆疊stack中。
我們重複這個過程，直到堆疊stack為空，即已經訪問過所有節點或者找到了目標節點。

## 複雜度

### 時間複雜度

$O(V+E)$
最壞情況下，DFS可以訪問所有節點和邊，因此時間複雜度為$O(V+E)$，其中`V`表示節點數，`E`表示邊數。

### 空間複雜度

$O(V)$
在最壞情況下，如果樹或圖是連通的，`DFS`可能會將整個樹或圖遍歷，因此空間複雜度為$O(V)$，其中`V`表示節點數。

如果使用遞歸實現`DFS`，那麼空間複雜度取決於堆疊(STACK)的最大深度，最壞情況下也是$O(V)$。

## 實戰

### 題目說明

給定一棵二元樹，找到它的最小深度。 最小深度是從根節點到最近的葉節點的最短路徑上的節點數。

![](https://i.imgur.com/STLdudZ.jpg)

### 解題

通過遞迴的方式進行深度優先搜索（DFS）來計算二元數的最小深度，並比較左子樹和右子樹的深度，最終返回二元樹的最小深度。

遞迴終止條件有三種情況： 

1. 當 `root` 為 `null` 時，表示遍歷到了空節點，直接返回深度 0。
1. 當 `root` 的左子節點為 `null` 時，表示只有右子樹，繼續遞歸計算右子樹的最小深度，並加上當前節點，返回深度加 1。
1. 當 `root` 的右子節點為 `null` 時，表示只有左子樹，繼續遞歸計算左子樹的最小深度，並加上當前節點，返回深度加 1。

如果以上三種情況都不滿足，說明當前節點既有左子樹又有右子樹，此時取左子樹和右子樹的最小深度的較小值，並返回深度加 1 (當前節點)，即為最終的最小深度。

```javascript=
/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number}
 */
var minDepth = function(root) {
    if (root == null) return 0;
    if (root.left == null) return minDepth(root.right) + 1
    if (root.right == null) return minDepth(root.left) + 1
    return Math.min(minDepth(root.left), minDepth(root.right)) + 1
};
```