演算法筆記-Tree-1
Tree
由 n 個有限節點組成一個具有層次關係的集合,形狀類似一顆倒著的樹,具有以下幾個特點:
- 沒有環 (cycle)。
- 所有點之間連通,且只有唯一路徑。
- 邊數 = 點數 - 1。
Binary Tree
每個節點的度數不大於 2 的樹,左右的分支分別稱為 左子樹與右子樹,並且左右子樹有次序關係,不能隨意交換。
遍歷
- 前序遍歷 (根結點 -> 左子樹 -> 右子樹)
- 中序遍歷 (左子樹 -> 根結點 -> 右子樹)
- 後序遍歷 (左子樹 -> 右子樹 -> 根結點)
1 | void treeTraversal(TreeNode* root) { |
- 層序遍歷
紀錄queue的大小,每次處理一整層的元素。
1 | void levelOrder(TreeNode* root) { |
還原
透過二叉樹的遍歷結果回推原始二叉樹的結構。
前序 + 中序
前序遍歷的順序為 [根結點、左子樹、右子樹],而中序遍歷的順序為 [左子樹、根結點、右子樹],因此我們可以透過前序遍歷的第一個元素找到根結點,將其帶入中序遍歷,就可以找到左、右子樹,對左、右子樹遞迴進行此行為就可以構造出原始樹。
1 | TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) { |
後序 + 中序
與前序 + 中序類似,因此我們可以透過後序遍歷的最後一個元素找到根結點,將其帶入中序遍歷,就可以找到左、右子樹,對左、右子樹遞迴進行此行為就可以構造出原始樹。
1 | TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) { |
前序 + 後序
因為無法確定左右子樹的區分,因此構造出的樹不唯一,這邊假設前序遍歷的第二個元素 preorder[1] 是左子樹的根結點,可以構造出其中一種樹。
1 | TreeNode* constructFromPrePost(vector<int>& preorder, vector<int>& postorder) { |
練習
LeetCode 112. Path Sum
Given the root of a binary tree and an integer targetSum, return true if the tree has a root-to-leaf path such that adding up all the values along the path equals targetSum.
A leaf is a node with no children.
Example 1:
Input: root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22
Output: true
Example 2:
Input: root = [1,2,3], targetSum = 5
Output: false
Example 3:
Input: root = [], targetSum = 0
Output: false
Solution:
1 | class Solution { |
如果當前節點為葉節點且離 targetSum 的差距為 0,代表滿足目標,否則將 targetSum - root -> val 作為參數傳入左右節點,並遞迴判斷是否成立。
LeetCode 236. Lowest Common Ancestor of a Binary Tree
Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree.
According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants (where we allow a node to be a descendant of itself).”
Example 1:
Input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
Output: 3
Example 2:
Input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
Output: 5
Example 3:
Input: root = [1,2], p = 1, q = 2
Output: 1
Solution:
1 | class Solution { |
如果函數回傳的值為nullptr 代表 p,q 都不在這個子樹中,因此根據左右子樹帶入函數的值,可以區分為以下幾種情形:
l != nullptr && r != nullptr代表p,q分別位於左右子樹,則該節點為最低共同祖先。l == nullptr && r != nullptr代表p,q都位於右子樹。l != nullptr && r !== nullptr代表p,q都位於左子樹。l != nullptr && r != nullptr代表p,q不在這個子樹中。
LeetCode 124. Binary Tree Maximum Path Sum
A path in a binary tree is a sequence of nodes where each pair of adjacent nodes in the sequence has an edge connecting them. A node can only appear in the sequence at most once. Note that the path does not need to pass through the root.
The path sum of a path is the sum of the node’s values in the path.
Given the root of a binary tree, return the maximum path sum of any non-empty path.
Example 1:
Input: root = [1,2,3]
Output: 6
Example 2:
Input: root = [-10,9,20,null,null,15,7]
Output: 42
Solution:
1 | class Solution { |
pathSum 函數代表以此節點為根的最大貢獻路徑長,每次遞迴包含以下過程:
- 如果此點為空節點,返回 0。
- 計算
left為左子樹貢獻的最大長度,如果值為負數則直接捨棄 (路徑不包含左子樹)。 - 計算
right為右子樹貢獻的最大長度,如果值為負數則直接捨棄 (路徑不包含右子樹)。 以此節點為根的最大路徑和為left + right + root -> val,並且與當前最大值比較。- 回傳
以此節點為根的最大貢獻路徑長,值為max(left, right) + root -> val。
LeetCode 297. Serialize and Deserialize Binary Tree
Serialization is the process of converting a data structure or object into a sequence of bits so that it can be stored in a file or memory buffer, or transmitted across a network connection link to be reconstructed later in the same or another computer environment.
Design an algorithm to serialize and deserialize a binary tree. There is no restriction on how your serialization/deserialization algorithm should work. You just need to ensure that a binary tree can be serialized to a string and this string can be deserialized to the original tree structure.
Clarification: The input/output format is the same as how LeetCode serializes a binary tree. You do not necessarily need to follow this format, so please be creative and come up with different approaches yourself.
Example 1:
Input: root = [1,2,3,null,null,4,5]
Output: [1,2,3,null,null,4,5]
Example 2:
Input: root = []
Output: []
Solution:
1 | class Codec { |
-
編碼
使用前序遍歷,將二叉樹的值儲存為字串,如果遇到空節點,則加入"null"。 -
解碼
使用queue儲存每個字串,並且利用dfs將值依序填入根結點、左子樹、右子樹中。





