啟動workman stream_socket_server() has been disabled for security reasons
回溯法有“通用解題法”之稱。用它可以系統地搜尋問題的所有解。
回溯法是一個既帶有系統性又帶有跳躍性的搜尋演算法。它在問題的解空間樹中,按深度優先策略,從根結點出發搜尋解空間樹。演算法搜尋至解空間樹的任一結點時,先判斷該結點是否包含問題的解。如果肯定不包含,則跳過對以該結點為根的子樹的搜尋,逐層向其祖先結點回溯;否則,進入該子樹,繼續按深度優先策略搜尋。
回溯法求問題的所有解時,要回溯到根,且根結點的所有子樹都被搜尋遍才結束。回溯法求問題的一個解時,只要搜尋到問題的一個解就可結束。
這種以深度優先方式系統搜尋問題解的演算法稱為回溯法,它適用於求解組合數較大的問題。也經常適用於求解二叉樹的相關問題,例如以下兩個二叉樹路徑總和的問題:
二叉樹是否存在某一路徑總和
示例:
給定如下二叉樹,以及目標和 sum = 22
,
5 / \ 4 8 (左)sum = sum - 5 = 17 / / \ 11 13 4 (左)sum = sum - 4 = 13 / \ \ 7 2 1 (左)sum = sum - 11 = 2
返回 true
, 因為存在目標和為 22 的根節點到葉子節點的路徑 5->4->11->2
。
使用遞迴,分別遍歷左右子樹,當左右子樹中有一個路徑滿足條件,則返回true
遞迴結束條件:root.left == null && root.right == null && sum == root.val
sum的值自頂向下 逐層遞減 sum = sum - root.val。
class Solution { public boolean hasPathSum(TreeNode root, int sum) { // 當前節點為空,sum 大於等於 0;例如:root = [],sum = 0、sum = 1 if (root == null && sum >= 0) { return false; } // 當前節點為空,sum 小於 0;例如:root = [],sum = -1 if (root == null && sum < 0) { return false; } // 當且僅當 左右孩子節點為空 且 sum = root.val 時,則找到目標 if (root.left == null && root.right == null && sum == root.val) { return true; } // 遍歷目標節點的左子樹和右子樹 ,當左右子樹中有一個返回true(即找到目標) 時,則返回true; // sum = sum - root.val,當到達葉子節點且sum= root.val則 找到目標 return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val); } }
二叉樹路徑總和為某值的所有路徑
輸入一棵二叉樹和一個整數,打印出二叉樹中節點值的和為輸入整數的所有路徑。從樹的根節點開始往下一直到葉節點所經過的節點形成一條路徑。
示例:
給定如下二叉樹,以及目標和 sum = 22
,
5
/ \
4 8
/ / \
11 13 4
/ \ / \
7 2 5 1
返回:
[
[5,4,11,2],
[5,8,4,5]
]
提示:
節點總數 <= 10000
解題思路:從根節點開始遞迴遍歷,每遍歷一個節點,則把當前節點入棧。
同時判斷 sum == 當前節點.val(每遍歷一個節點時,其sum = sum - 父節點.val)。
如果到達葉子節點且sum = 當前節點.val,則說明找到了正確的路徑,就將棧內的所有元素儲存到連結串列中。
每次返回父節點前都要將棧頂的節點刪除再返回父節點。
class Solution {
List<List<Integer>> resList = new ArrayList<>();
LinkedList<TreeNode> stack = new LinkedList<>();
public List<List<Integer>> pathSum(TreeNode root, int sum) {
if (root == null) {
return new ArrayList<>();
}
findPath(root, sum);
return resList;
}
public void findPath(TreeNode root, int currentSum) {
// 將當前根節點入棧
stack.push(root);
// 判斷節點狀態及sum數值,找到合適的路徑就將棧內元素儲存到連結串列中
if ((root.left == null && root.right == null) && currentSum == root.val) {
ArrayList<Integer> list = new ArrayList<>();
for (int i = stack.size() - 1; i >= 0; i--) {
TreeNode node = stack.get(i);
list.add(node.val);
}
resList.add(list);
}
// 如果不是葉子節點,則繼續遍歷其子節點
if (root.left != null) {
findPath(root.left, currentSum - root.val);
}
if (root.right != null) {
findPath(root.right, currentSum - root.val);
}
// 遞迴返回其父節點前,將棧內路徑上的當前節點刪除
stack.pop();
}
}