 Hello 算法 1.2.0 繁体中文 C语言 版13.1.1 嘗試與回退 之所以稱之為回溯演算法,是因為該演算法在搜尋解空間時會採用“嘗試”與“回退”的策略。當演算法在 搜尋過程中遇到某個狀態無法繼續前進或無法得到滿足條件的解時,它會撤銷上一步的選擇,退回到之前的 狀態,並嘗試其他可能的選擇。 對於例題一,訪問每個節點都代表一次“嘗試”,而越過葉節點或返回父節點的 return 則表示“回退”。 值得說明的是,回退並不僅僅包括函式返回。為解釋這一點,我們對例題一稍作拓展。 preOrder(root->left); preOrder(root->right); // 回退 pathSize--; } 在每次“嘗試”中,我們透過將當前節點新增進 path 來記錄路徑;而在“回退”前,我們需要將該節點從 path 中彈出,以恢復本次嘗試之前的狀態。 觀察圖 13‑2 所示的過程,我們可以將嘗試和回退理解為“前進”與“撤銷”,兩個操作互為逆向。 第 13 章 回溯 www.hello‑algo hello‑algo.com 286 第 13 章 回溯 www.hello‑algo.com 287 圖 13‑2 嘗試與回退 13.1.2 剪枝 複雜的回溯問題通常包含一個或多個約束條件,約束條件通常可用於“剪枝”。 例題三 在二元樹中搜索所有值為 7 的節點,請返回根節點到這些節點的路徑,並要求路徑中不包含值為 3 的 節點。 為了滿足以上約束條件,我們需要新增剪枝操作:在搜尋過程中,若遇到值為0 码力 | 392 页 | 18.83 MB | 10 月前3 Hello 算法 1.2.0 繁体中文 C语言 版13.1.1 嘗試與回退 之所以稱之為回溯演算法,是因為該演算法在搜尋解空間時會採用“嘗試”與“回退”的策略。當演算法在 搜尋過程中遇到某個狀態無法繼續前進或無法得到滿足條件的解時,它會撤銷上一步的選擇,退回到之前的 狀態,並嘗試其他可能的選擇。 對於例題一,訪問每個節點都代表一次“嘗試”,而越過葉節點或返回父節點的 return 則表示“回退”。 值得說明的是,回退並不僅僅包括函式返回。為解釋這一點,我們對例題一稍作拓展。 preOrder(root->left); preOrder(root->right); // 回退 pathSize--; } 在每次“嘗試”中,我們透過將當前節點新增進 path 來記錄路徑;而在“回退”前,我們需要將該節點從 path 中彈出,以恢復本次嘗試之前的狀態。 觀察圖 13‑2 所示的過程,我們可以將嘗試和回退理解為“前進”與“撤銷”,兩個操作互為逆向。 第 13 章 回溯 www.hello‑algo hello‑algo.com 286 第 13 章 回溯 www.hello‑algo.com 287 圖 13‑2 嘗試與回退 13.1.2 剪枝 複雜的回溯問題通常包含一個或多個約束條件,約束條件通常可用於“剪枝”。 例題三 在二元樹中搜索所有值為 7 的節點,請返回根節點到這些節點的路徑,並要求路徑中不包含值為 3 的 節點。 為了滿足以上約束條件,我們需要新增剪枝操作:在搜尋過程中,若遇到值為0 码力 | 392 页 | 18.83 MB | 10 月前3
 Hello 算法 1.2.0 繁体中文 C# 版13.1.1 嘗試與回退 之所以稱之為回溯演算法,是因為該演算法在搜尋解空間時會採用“嘗試”與“回退”的策略。當演算法在 搜尋過程中遇到某個狀態無法繼續前進或無法得到滿足條件的解時,它會撤銷上一步的選擇,退回到之前的 狀態,並嘗試其他可能的選擇。 對於例題一,訪問每個節點都代表一次“嘗試”,而越過葉節點或返回父節點的 return 則表示“回退”。 值得說明的是,回退並不僅僅包括函式返回。為解釋這一點,我們對例題一稍作拓展。 left); PreOrder(root.right); // 回退 path.RemoveAt(path.Count - 1); } 在每次“嘗試”中,我們透過將當前節點新增進 path 來記錄路徑;而在“回退”前,我們需要將該節點從 path 中彈出,以恢復本次嘗試之前的狀態。 觀察圖 13‑2 所示的過程,我們可以將嘗試和回退理解為“前進”與“撤銷”,兩個操作互為逆向。 第 13 章 章 回溯 www.hello‑algo.com 276 圖 13‑2 嘗試與回退 第 13 章 回溯 www.hello‑algo.com 277 13.1.2 剪枝 複雜的回溯問題通常包含一個或多個約束條件,約束條件通常可用於“剪枝”。 例題三 在二元樹中搜索所有值為 7 的節點,請返回根節點到這些節點的路徑,並要求路徑中不包含值為 3 的 節點。 為了滿足以上約束條件,我們需要新增剪枝操作:在搜尋過程中,若遇到值為0 码力 | 379 页 | 18.79 MB | 10 月前3 Hello 算法 1.2.0 繁体中文 C# 版13.1.1 嘗試與回退 之所以稱之為回溯演算法,是因為該演算法在搜尋解空間時會採用“嘗試”與“回退”的策略。當演算法在 搜尋過程中遇到某個狀態無法繼續前進或無法得到滿足條件的解時,它會撤銷上一步的選擇,退回到之前的 狀態,並嘗試其他可能的選擇。 對於例題一,訪問每個節點都代表一次“嘗試”,而越過葉節點或返回父節點的 return 則表示“回退”。 值得說明的是,回退並不僅僅包括函式返回。為解釋這一點,我們對例題一稍作拓展。 left); PreOrder(root.right); // 回退 path.RemoveAt(path.Count - 1); } 在每次“嘗試”中,我們透過將當前節點新增進 path 來記錄路徑;而在“回退”前,我們需要將該節點從 path 中彈出,以恢復本次嘗試之前的狀態。 觀察圖 13‑2 所示的過程,我們可以將嘗試和回退理解為“前進”與“撤銷”,兩個操作互為逆向。 第 13 章 章 回溯 www.hello‑algo.com 276 圖 13‑2 嘗試與回退 第 13 章 回溯 www.hello‑algo.com 277 13.1.2 剪枝 複雜的回溯問題通常包含一個或多個約束條件,約束條件通常可用於“剪枝”。 例題三 在二元樹中搜索所有值為 7 的節點,請返回根節點到這些節點的路徑,並要求路徑中不包含值為 3 的 節點。 為了滿足以上約束條件,我們需要新增剪枝操作:在搜尋過程中,若遇到值為0 码力 | 379 页 | 18.79 MB | 10 月前3
 Hello 算法 1.2.0 繁体中文 Dart 版13.1.1 嘗試與回退 之所以稱之為回溯演算法,是因為該演算法在搜尋解空間時會採用“嘗試”與“回退”的策略。當演算法在 搜尋過程中遇到某個狀態無法繼續前進或無法得到滿足條件的解時,它會撤銷上一步的選擇,退回到之前的 狀態,並嘗試其他可能的選擇。 對於例題一,訪問每個節點都代表一次“嘗試”,而越過葉節點或返回父節點的 return 則表示“回退”。 值得說明的是,回退並不僅僅包括函式返回。為解釋這一點,我們對例題一稍作拓展。 preOrder(root.right, path, res); // 回退 path.removeLast(); } 在每次“嘗試”中,我們透過將當前節點新增進 path 來記錄路徑;而在“回退”前,我們需要將該節點從 path 中彈出,以恢復本次嘗試之前的狀態。 觀察圖 13‑2 所示的過程,我們可以將嘗試和回退理解為“前進”與“撤銷”,兩個操作互為逆向。 第 13 章 回溯 www www.hello‑algo.com 275 第 13 章 回溯 www.hello‑algo.com 276 圖 13‑2 嘗試與回退 13.1.2 剪枝 複雜的回溯問題通常包含一個或多個約束條件,約束條件通常可用於“剪枝”。 例題三 在二元樹中搜索所有值為 7 的節點,請返回根節點到這些節點的路徑,並要求路徑中不包含值為 3 的 節點。 為了滿足以上約束條件,我們需要新增剪枝操作:在搜尋過程中,若遇到值為0 码力 | 378 页 | 18.77 MB | 10 月前3 Hello 算法 1.2.0 繁体中文 Dart 版13.1.1 嘗試與回退 之所以稱之為回溯演算法,是因為該演算法在搜尋解空間時會採用“嘗試”與“回退”的策略。當演算法在 搜尋過程中遇到某個狀態無法繼續前進或無法得到滿足條件的解時,它會撤銷上一步的選擇,退回到之前的 狀態,並嘗試其他可能的選擇。 對於例題一,訪問每個節點都代表一次“嘗試”,而越過葉節點或返回父節點的 return 則表示“回退”。 值得說明的是,回退並不僅僅包括函式返回。為解釋這一點,我們對例題一稍作拓展。 preOrder(root.right, path, res); // 回退 path.removeLast(); } 在每次“嘗試”中,我們透過將當前節點新增進 path 來記錄路徑;而在“回退”前,我們需要將該節點從 path 中彈出,以恢復本次嘗試之前的狀態。 觀察圖 13‑2 所示的過程,我們可以將嘗試和回退理解為“前進”與“撤銷”,兩個操作互為逆向。 第 13 章 回溯 www www.hello‑algo.com 275 第 13 章 回溯 www.hello‑algo.com 276 圖 13‑2 嘗試與回退 13.1.2 剪枝 複雜的回溯問題通常包含一個或多個約束條件,約束條件通常可用於“剪枝”。 例題三 在二元樹中搜索所有值為 7 的節點,請返回根節點到這些節點的路徑,並要求路徑中不包含值為 3 的 節點。 為了滿足以上約束條件,我們需要新增剪枝操作:在搜尋過程中,若遇到值為0 码力 | 378 页 | 18.77 MB | 10 月前3
 Hello 算法 1.2.0 繁体中文 Go 版13.1.1 嘗試與回退 之所以稱之為回溯演算法,是因為該演算法在搜尋解空間時會採用“嘗試”與“回退”的策略。當演算法在 搜尋過程中遇到某個狀態無法繼續前進或無法得到滿足條件的解時,它會撤銷上一步的選擇,退回到之前的 狀態,並嘗試其他可能的選擇。 對於例題一,訪問每個節點都代表一次“嘗試”,而越過葉節點或返回父節點的 return 則表示“回退”。 值得說明的是,回退並不僅僅包括函式返回。為解釋這一點,我們對例題一稍作拓展。 preOrderII(root.Right, res, path) // 回退 *path = (*path)[:len(*path)-1] } 在每次“嘗試”中,我們透過將當前節點新增進 path 來記錄路徑;而在“回退”前,我們需要將該節點從 path 中彈出,以恢復本次嘗試之前的狀態。 觀察圖 13‑2 所示的過程,我們可以將嘗試和回退理解為“前進”與“撤銷”,兩個操作互為逆向。 第 13 章 章 回溯 www.hello‑algo.com 280 圖 13‑2 嘗試與回退 第 13 章 回溯 www.hello‑algo.com 281 13.1.2 剪枝 複雜的回溯問題通常包含一個或多個約束條件,約束條件通常可用於“剪枝”。 例題三 在二元樹中搜索所有值為 7 的節點,請返回根節點到這些節點的路徑,並要求路徑中不包含值為 3 的 節點。 為了滿足以上約束條件,我們需要新增剪枝操作:在搜尋過程中,若遇到值為0 码力 | 385 页 | 18.80 MB | 10 月前3 Hello 算法 1.2.0 繁体中文 Go 版13.1.1 嘗試與回退 之所以稱之為回溯演算法,是因為該演算法在搜尋解空間時會採用“嘗試”與“回退”的策略。當演算法在 搜尋過程中遇到某個狀態無法繼續前進或無法得到滿足條件的解時,它會撤銷上一步的選擇,退回到之前的 狀態,並嘗試其他可能的選擇。 對於例題一,訪問每個節點都代表一次“嘗試”,而越過葉節點或返回父節點的 return 則表示“回退”。 值得說明的是,回退並不僅僅包括函式返回。為解釋這一點,我們對例題一稍作拓展。 preOrderII(root.Right, res, path) // 回退 *path = (*path)[:len(*path)-1] } 在每次“嘗試”中,我們透過將當前節點新增進 path 來記錄路徑;而在“回退”前,我們需要將該節點從 path 中彈出,以恢復本次嘗試之前的狀態。 觀察圖 13‑2 所示的過程,我們可以將嘗試和回退理解為“前進”與“撤銷”,兩個操作互為逆向。 第 13 章 章 回溯 www.hello‑algo.com 280 圖 13‑2 嘗試與回退 第 13 章 回溯 www.hello‑algo.com 281 13.1.2 剪枝 複雜的回溯問題通常包含一個或多個約束條件,約束條件通常可用於“剪枝”。 例題三 在二元樹中搜索所有值為 7 的節點,請返回根節點到這些節點的路徑,並要求路徑中不包含值為 3 的 節點。 為了滿足以上約束條件,我們需要新增剪枝操作:在搜尋過程中,若遇到值為0 码力 | 385 页 | 18.80 MB | 10 月前3
 Hello 算法 1.2.0 繁体中文 Kotlin 版13.1.1 嘗試與回退 之所以稱之為回溯演算法,是因為該演算法在搜尋解空間時會採用“嘗試”與“回退”的策略。當演算法在 搜尋過程中遇到某個狀態無法繼續前進或無法得到滿足條件的解時,它會撤銷上一步的選擇,退回到之前的 狀態,並嘗試其他可能的選擇。 對於例題一,訪問每個節點都代表一次“嘗試”,而越過葉節點或返回父節點的 return 則表示“回退”。 值得說明的是,回退並不僅僅包括函式返回。為解釋這一點,我們對例題一稍作拓展。 left) preOrder(root.right) // 回退 path!!.removeAt(path!!.size - 1) } 在每次“嘗試”中,我們透過將當前節點新增進 path 來記錄路徑;而在“回退”前,我們需要將該節點從 path 中彈出,以恢復本次嘗試之前的狀態。 觀察圖 13‑2 所示的過程,我們可以將嘗試和回退理解為“前進”與“撤銷”,兩個操作互為逆向。 第 13 章 章 回溯 www.hello‑algo.com 278 圖 13‑2 嘗試與回退 第 13 章 回溯 www.hello‑algo.com 279 13.1.2 剪枝 複雜的回溯問題通常包含一個或多個約束條件,約束條件通常可用於“剪枝”。 例題三 在二元樹中搜索所有值為 7 的節點,請返回根節點到這些節點的路徑,並要求路徑中不包含值為 3 的 節點。 為了滿足以上約束條件,我們需要新增剪枝操作:在搜尋過程中,若遇到值為0 码力 | 382 页 | 18.79 MB | 10 月前3 Hello 算法 1.2.0 繁体中文 Kotlin 版13.1.1 嘗試與回退 之所以稱之為回溯演算法,是因為該演算法在搜尋解空間時會採用“嘗試”與“回退”的策略。當演算法在 搜尋過程中遇到某個狀態無法繼續前進或無法得到滿足條件的解時,它會撤銷上一步的選擇,退回到之前的 狀態,並嘗試其他可能的選擇。 對於例題一,訪問每個節點都代表一次“嘗試”,而越過葉節點或返回父節點的 return 則表示“回退”。 值得說明的是,回退並不僅僅包括函式返回。為解釋這一點,我們對例題一稍作拓展。 left) preOrder(root.right) // 回退 path!!.removeAt(path!!.size - 1) } 在每次“嘗試”中,我們透過將當前節點新增進 path 來記錄路徑;而在“回退”前,我們需要將該節點從 path 中彈出,以恢復本次嘗試之前的狀態。 觀察圖 13‑2 所示的過程,我們可以將嘗試和回退理解為“前進”與“撤銷”,兩個操作互為逆向。 第 13 章 章 回溯 www.hello‑algo.com 278 圖 13‑2 嘗試與回退 第 13 章 回溯 www.hello‑algo.com 279 13.1.2 剪枝 複雜的回溯問題通常包含一個或多個約束條件,約束條件通常可用於“剪枝”。 例題三 在二元樹中搜索所有值為 7 的節點,請返回根節點到這些節點的路徑,並要求路徑中不包含值為 3 的 節點。 為了滿足以上約束條件,我們需要新增剪枝操作:在搜尋過程中,若遇到值為0 码力 | 382 页 | 18.79 MB | 10 月前3
 Hello 算法 1.2.0 繁体中文 Java 版13.1.1 嘗試與回退 之所以稱之為回溯演算法,是因為該演算法在搜尋解空間時會採用“嘗試”與“回退”的策略。當演算法在 搜尋過程中遇到某個狀態無法繼續前進或無法得到滿足條件的解時,它會撤銷上一步的選擇,退回到之前的 狀態,並嘗試其他可能的選擇。 對於例題一,訪問每個節點都代表一次“嘗試”,而越過葉節點或返回父節點的 return 則表示“回退”。 值得說明的是,回退並不僅僅包括函式返回。為解釋這一點,我們對例題一稍作拓展。 left); preOrder(root.right); // 回退 path.remove(path.size() - 1); } 在每次“嘗試”中,我們透過將當前節點新增進 path 來記錄路徑;而在“回退”前,我們需要將該節點從 path 中彈出,以恢復本次嘗試之前的狀態。 觀察圖 13‑2 所示的過程,我們可以將嘗試和回退理解為“前進”與“撤銷”,兩個操作互為逆向。 第 13 章 回溯 回溯 www.hello‑algo.com 276 圖 13‑2 嘗試與回退 第 13 章 回溯 www.hello‑algo.com 277 13.1.2 剪枝 複雜的回溯問題通常包含一個或多個約束條件,約束條件通常可用於“剪枝”。 例題三 在二元樹中搜索所有值為 7 的節點,請返回根節點到這些節點的路徑,並要求路徑中不包含值為 3 的 節點。 為了滿足以上約束條件,我們需要新增剪枝操作:在搜尋過程中,若遇到值為0 码力 | 379 页 | 18.79 MB | 10 月前3 Hello 算法 1.2.0 繁体中文 Java 版13.1.1 嘗試與回退 之所以稱之為回溯演算法,是因為該演算法在搜尋解空間時會採用“嘗試”與“回退”的策略。當演算法在 搜尋過程中遇到某個狀態無法繼續前進或無法得到滿足條件的解時,它會撤銷上一步的選擇,退回到之前的 狀態,並嘗試其他可能的選擇。 對於例題一,訪問每個節點都代表一次“嘗試”,而越過葉節點或返回父節點的 return 則表示“回退”。 值得說明的是,回退並不僅僅包括函式返回。為解釋這一點,我們對例題一稍作拓展。 left); preOrder(root.right); // 回退 path.remove(path.size() - 1); } 在每次“嘗試”中,我們透過將當前節點新增進 path 來記錄路徑;而在“回退”前,我們需要將該節點從 path 中彈出,以恢復本次嘗試之前的狀態。 觀察圖 13‑2 所示的過程,我們可以將嘗試和回退理解為“前進”與“撤銷”,兩個操作互為逆向。 第 13 章 回溯 回溯 www.hello‑algo.com 276 圖 13‑2 嘗試與回退 第 13 章 回溯 www.hello‑algo.com 277 13.1.2 剪枝 複雜的回溯問題通常包含一個或多個約束條件,約束條件通常可用於“剪枝”。 例題三 在二元樹中搜索所有值為 7 的節點,請返回根節點到這些節點的路徑,並要求路徑中不包含值為 3 的 節點。 為了滿足以上約束條件,我們需要新增剪枝操作:在搜尋過程中,若遇到值為0 码力 | 379 页 | 18.79 MB | 10 月前3
 Hello 算法 1.2.0 繁体中文 JavaScript 版13.1.1 嘗試與回退 之所以稱之為回溯演算法,是因為該演算法在搜尋解空間時會採用“嘗試”與“回退”的策略。當演算法在 搜尋過程中遇到某個狀態無法繼續前進或無法得到滿足條件的解時,它會撤銷上一步的選擇,退回到之前的 狀態,並嘗試其他可能的選擇。 對於例題一,訪問每個節點都代表一次“嘗試”,而越過葉節點或返回父節點的 return 則表示“回退”。 值得說明的是,回退並不僅僅包括函式返回。為解釋這一點,我們對例題一稍作拓展。 // 回退 path.pop(); } 在每次“嘗試”中,我們透過將當前節點新增進 path 來記錄路徑;而在“回退”前,我們需要將該節點從 path 中彈出,以恢復本次嘗試之前的狀態。 觀察圖 13‑2 所示的過程,我們可以將嘗試和回退理解為“前進”與“撤銷”,兩個操作互為逆向。 第 13 章 回溯 www.hello‑algo.com 276 圖 13‑2 嘗試與回退 第 13 res); // 回退 path.pop(); } “剪枝”是一個非常形象的名詞。如圖 13‑3 所示,在搜尋過程中,我們“剪掉”了不滿足約束條件的搜尋分 支,避免許多無意義的嘗試,從而提高了搜尋效率。 圖 13‑3 根據約束條件剪枝 第 13 章 回溯 www.hello‑algo.com 278 13.1.3 框架程式碼 接下來,我們嘗試將回溯的“嘗試、回退、剪枝”的主體框架提煉出來,提升程式碼的通用性。0 码力 | 379 页 | 18.78 MB | 10 月前3 Hello 算法 1.2.0 繁体中文 JavaScript 版13.1.1 嘗試與回退 之所以稱之為回溯演算法,是因為該演算法在搜尋解空間時會採用“嘗試”與“回退”的策略。當演算法在 搜尋過程中遇到某個狀態無法繼續前進或無法得到滿足條件的解時,它會撤銷上一步的選擇,退回到之前的 狀態,並嘗試其他可能的選擇。 對於例題一,訪問每個節點都代表一次“嘗試”,而越過葉節點或返回父節點的 return 則表示“回退”。 值得說明的是,回退並不僅僅包括函式返回。為解釋這一點,我們對例題一稍作拓展。 // 回退 path.pop(); } 在每次“嘗試”中,我們透過將當前節點新增進 path 來記錄路徑;而在“回退”前,我們需要將該節點從 path 中彈出,以恢復本次嘗試之前的狀態。 觀察圖 13‑2 所示的過程,我們可以將嘗試和回退理解為“前進”與“撤銷”,兩個操作互為逆向。 第 13 章 回溯 www.hello‑algo.com 276 圖 13‑2 嘗試與回退 第 13 res); // 回退 path.pop(); } “剪枝”是一個非常形象的名詞。如圖 13‑3 所示,在搜尋過程中,我們“剪掉”了不滿足約束條件的搜尋分 支,避免許多無意義的嘗試,從而提高了搜尋效率。 圖 13‑3 根據約束條件剪枝 第 13 章 回溯 www.hello‑algo.com 278 13.1.3 框架程式碼 接下來,我們嘗試將回溯的“嘗試、回退、剪枝”的主體框架提煉出來,提升程式碼的通用性。0 码力 | 379 页 | 18.78 MB | 10 月前3
 Hello 算法 1.2.0 繁体中文 TypeScript 版13.1.1 嘗試與回退 之所以稱之為回溯演算法,是因為該演算法在搜尋解空間時會採用“嘗試”與“回退”的策略。當演算法在 搜尋過程中遇到某個狀態無法繼續前進或無法得到滿足條件的解時,它會撤銷上一步的選擇,退回到之前的 狀態,並嘗試其他可能的選擇。 對於例題一,訪問每個節點都代表一次“嘗試”,而越過葉節點或返回父節點的 return 則表示“回退”。 值得說明的是,回退並不僅僅包括函式返回。為解釋這一點,我們對例題一稍作拓展。 res); preOrder(root.right, path, res); // 回退 path.pop(); } 在每次“嘗試”中,我們透過將當前節點新增進 path 來記錄路徑;而在“回退”前,我們需要將該節點從 path 中彈出,以恢復本次嘗試之前的狀態。 觀察圖 13‑2 所示的過程,我們可以將嘗試和回退理解為“前進”與“撤銷”,兩個操作互為逆向。 第 13 章 回溯 www.hello‑algo hello‑algo.com 279 第 13 章 回溯 www.hello‑algo.com 280 圖 13‑2 嘗試與回退 13.1.2 剪枝 複雜的回溯問題通常包含一個或多個約束條件,約束條件通常可用於“剪枝”。 例題三 在二元樹中搜索所有值為 7 的節點,請返回根節點到這些節點的路徑,並要求路徑中不包含值為 3 的 節點。 為了滿足以上約束條件,我們需要新增剪枝操作:在搜尋過程中,若遇到值為0 码力 | 384 页 | 18.80 MB | 10 月前3 Hello 算法 1.2.0 繁体中文 TypeScript 版13.1.1 嘗試與回退 之所以稱之為回溯演算法,是因為該演算法在搜尋解空間時會採用“嘗試”與“回退”的策略。當演算法在 搜尋過程中遇到某個狀態無法繼續前進或無法得到滿足條件的解時,它會撤銷上一步的選擇,退回到之前的 狀態,並嘗試其他可能的選擇。 對於例題一,訪問每個節點都代表一次“嘗試”,而越過葉節點或返回父節點的 return 則表示“回退”。 值得說明的是,回退並不僅僅包括函式返回。為解釋這一點,我們對例題一稍作拓展。 res); preOrder(root.right, path, res); // 回退 path.pop(); } 在每次“嘗試”中,我們透過將當前節點新增進 path 來記錄路徑;而在“回退”前,我們需要將該節點從 path 中彈出,以恢復本次嘗試之前的狀態。 觀察圖 13‑2 所示的過程,我們可以將嘗試和回退理解為“前進”與“撤銷”,兩個操作互為逆向。 第 13 章 回溯 www.hello‑algo hello‑algo.com 279 第 13 章 回溯 www.hello‑algo.com 280 圖 13‑2 嘗試與回退 13.1.2 剪枝 複雜的回溯問題通常包含一個或多個約束條件,約束條件通常可用於“剪枝”。 例題三 在二元樹中搜索所有值為 7 的節點,請返回根節點到這些節點的路徑,並要求路徑中不包含值為 3 的 節點。 為了滿足以上約束條件,我們需要新增剪枝操作:在搜尋過程中,若遇到值為0 码力 | 384 页 | 18.80 MB | 10 月前3
 Hello 算法 1.2.0 繁体中文 Swift 版13.1.1 嘗試與回退 之所以稱之為回溯演算法,是因為該演算法在搜尋解空間時會採用“嘗試”與“回退”的策略。當演算法在 搜尋過程中遇到某個狀態無法繼續前進或無法得到滿足條件的解時,它會撤銷上一步的選擇,退回到之前的 狀態,並嘗試其他可能的選擇。 對於例題一,訪問每個節點都代表一次“嘗試”,而越過葉節點或返回父節點的 return 則表示“回退”。 值得說明的是,回退並不僅僅包括函式返回。為解釋這一點,我們對例題一稍作拓展。 left) preOrder(root: root.right) // 回退 path.removeLast() } 在每次“嘗試”中,我們透過將當前節點新增進 path 來記錄路徑;而在“回退”前,我們需要將該節點從 path 中彈出,以恢復本次嘗試之前的狀態。 觀察圖 13‑2 所示的過程,我們可以將嘗試和回退理解為“前進”與“撤銷”,兩個操作互為逆向。 第 13 章 回溯 www www.hello‑algo.com 276 圖 13‑2 嘗試與回退 第 13 章 回溯 www.hello‑algo.com 277 13.1.2 剪枝 複雜的回溯問題通常包含一個或多個約束條件,約束條件通常可用於“剪枝”。 例題三 在二元樹中搜索所有值為 7 的節點,請返回根節點到這些節點的路徑,並要求路徑中不包含值為 3 的 節點。 為了滿足以上約束條件,我們需要新增剪枝操作:在搜尋過程中,若遇到值為0 码力 | 379 页 | 18.79 MB | 10 月前3 Hello 算法 1.2.0 繁体中文 Swift 版13.1.1 嘗試與回退 之所以稱之為回溯演算法,是因為該演算法在搜尋解空間時會採用“嘗試”與“回退”的策略。當演算法在 搜尋過程中遇到某個狀態無法繼續前進或無法得到滿足條件的解時,它會撤銷上一步的選擇,退回到之前的 狀態,並嘗試其他可能的選擇。 對於例題一,訪問每個節點都代表一次“嘗試”,而越過葉節點或返回父節點的 return 則表示“回退”。 值得說明的是,回退並不僅僅包括函式返回。為解釋這一點,我們對例題一稍作拓展。 left) preOrder(root: root.right) // 回退 path.removeLast() } 在每次“嘗試”中,我們透過將當前節點新增進 path 來記錄路徑;而在“回退”前,我們需要將該節點從 path 中彈出,以恢復本次嘗試之前的狀態。 觀察圖 13‑2 所示的過程,我們可以將嘗試和回退理解為“前進”與“撤銷”,兩個操作互為逆向。 第 13 章 回溯 www www.hello‑algo.com 276 圖 13‑2 嘗試與回退 第 13 章 回溯 www.hello‑algo.com 277 13.1.2 剪枝 複雜的回溯問題通常包含一個或多個約束條件,約束條件通常可用於“剪枝”。 例題三 在二元樹中搜索所有值為 7 的節點,請返回根節點到這些節點的路徑,並要求路徑中不包含值為 3 的 節點。 為了滿足以上約束條件,我們需要新增剪枝操作:在搜尋過程中,若遇到值為0 码力 | 379 页 | 18.79 MB | 10 月前3
 Hello 算法 1.2.0 繁体中文 Ruby 版pre_order(root.left) pre_order(root.right) end 圖 13‑1 在前序走訪中搜索節點 13.1.1 嘗試與回退 之所以稱之為回溯演算法,是因為該演算法在搜尋解空間時會採用“嘗試”與“回退”的策略。當演算法在 搜尋過程中遇到某個狀態無法繼續前進或無法得到滿足條件的解時,它會撤銷上一步的選擇,退回到之前的 狀態,並嘗試其他可能的選擇。 第 13 13 章 回溯 www.hello‑algo.com 270 對於例題一,訪問每個節點都代表一次“嘗試”,而越過葉節點或返回父節點的 return 則表示“回退”。 值得說明的是,回退並不僅僅包括函式返回。為解釋這一點,我們對例題一稍作拓展。 例題二 在二元樹中搜索所有值為 7 的節點,請返回根節點到這些節點的路徑。 在例題一程式碼的基礎上,我們需要藉助一個串列 path 記錄訪問過的節點路徑。當訪問到值為 right) # 回退 $path.pop end 在每次“嘗試”中,我們透過將當前節點新增進 path 來記錄路徑;而在“回退”前,我們需要將該節點從 path 中彈出,以恢復本次嘗試之前的狀態。 觀察圖 13‑2 所示的過程,我們可以將嘗試和回退理解為“前進”與“撤銷”,兩個操作互為逆向。 第 13 章 回溯 www.hello‑algo.com 271 圖 13‑2 嘗試與回退 第 130 码力 | 372 页 | 18.75 MB | 10 月前3 Hello 算法 1.2.0 繁体中文 Ruby 版pre_order(root.left) pre_order(root.right) end 圖 13‑1 在前序走訪中搜索節點 13.1.1 嘗試與回退 之所以稱之為回溯演算法,是因為該演算法在搜尋解空間時會採用“嘗試”與“回退”的策略。當演算法在 搜尋過程中遇到某個狀態無法繼續前進或無法得到滿足條件的解時,它會撤銷上一步的選擇,退回到之前的 狀態,並嘗試其他可能的選擇。 第 13 13 章 回溯 www.hello‑algo.com 270 對於例題一,訪問每個節點都代表一次“嘗試”,而越過葉節點或返回父節點的 return 則表示“回退”。 值得說明的是,回退並不僅僅包括函式返回。為解釋這一點,我們對例題一稍作拓展。 例題二 在二元樹中搜索所有值為 7 的節點,請返回根節點到這些節點的路徑。 在例題一程式碼的基礎上,我們需要藉助一個串列 path 記錄訪問過的節點路徑。當訪問到值為 right) # 回退 $path.pop end 在每次“嘗試”中,我們透過將當前節點新增進 path 來記錄路徑;而在“回退”前,我們需要將該節點從 path 中彈出,以恢復本次嘗試之前的狀態。 觀察圖 13‑2 所示的過程,我們可以將嘗試和回退理解為“前進”與“撤銷”,兩個操作互為逆向。 第 13 章 回溯 www.hello‑algo.com 271 圖 13‑2 嘗試與回退 第 130 码力 | 372 页 | 18.75 MB | 10 月前3
共 14 条
- 1
- 2













