Java常用類庫:Class Math
阿新 • • 發佈:2021-02-08
技術標籤:LeetCode
94. 二叉樹的中序遍歷
題目描述
給定一個二叉樹的根節點 root
,返回它的 中序 遍歷。
示例 1:
輸入:root = [1,null,2,3]
輸出:[1,3,2]
示例 2:
輸入:root = []
輸出:[]
示例 3:
輸入:root = [1]
輸出:[1]
示例 4:
輸入:root = [1,2]
輸出:[2,1]
示例 5:
輸入:root = [1,null,2]
輸出:[1,2]
提示:
- 樹中節點數目在範圍
[0, 100]
內 -
−
100
≤
N
o
d
e
.
v
a
l
≤
100
-100 \le Node.val \le 100
進階: 遞迴演算法很簡單,你可以通過迭代演算法完成嗎?
題解:
二叉樹中序遍歷順序:左子樹、根節點、右子樹。
法一:
遞迴。
先遞迴左子樹,將根節點值加入答案,在遞迴右子樹。
時間複雜度: O ( n ) O(n) O(n)
額外空間複雜度: O ( n ) O(n) O(n)
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<int> ret;
void inorder(TreeNode* root) {
if ( root ) {
inorder( root->left );
ret.emplace_back( root->val );
inorder( root->right );
}
}
vector<int> inorderTraversal(TreeNode* root) {
inorder( root );
return ret;
}
};
/*
時間:0ms,擊敗:100.00%
記憶體:8.2MB,擊敗:81.82%
*/
法二:
迭代。
將 方法一 中的遞迴用非遞迴實現,因為遞迴過程中系統隱式地維護了一個棧,我們在迭代的時候需要顯示地將這個棧模擬出來。
時間複雜度: O ( n ) O(n) O(n)
額外空間複雜度: O ( n ) O(n) O(n)
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> ret;
stack<TreeNode*> stk;
while ( stk.size() || root ) {
while ( root ) {
stk.push( root );
root = root->left;
}
root = stk.top();
stk.pop();
ret.push_back( root->val );
root = root->right;
}
return ret;
}
};
/*
時間:0ms,擊敗:100.00%
記憶體:8.2MB,擊敗:82.80%
*/
法三:
Morris 遍歷。
普通遍歷的額外空間複雜度為
O
(
h
)
O(h)
O(h),h
為二叉樹高度。因為每個節點都有指向孩子節點的指標,所以從上層到下層容易,但是沒有指向父節點的指標,所以從下層到上層需要用棧來輔助完成。
而 Morris
遍歷的牛逼之處在於:通過讓底層節點指向 null
的空閒指標指向上層的某個節點,從而完成從下層到上層的移動。避免了使用棧結構,這種方法可以把額外空間複雜度優化到
O
(
1
)
O(1)
O(1)。
Morris
遍歷的實現原則,記當前的節點為 cur
:
-
如果
cur
無左孩子,cur
向右移動(cur = cur.right
) -
如果
cur
有左孩子,找到cur
左子樹上最右的節點,記為mostright
- 如果
mostright
的right
指標指向空,讓其指向cur
,cur
向左移動(cur = cur.left
) - 如果
mostright
的right
指標指向cur
,讓其指向空,cur
向右移動(cur = cur.right
)
- 如果
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> ret;
TreeNode *cur = root, *mostright = nullptr;
while ( cur ) {
if ( !cur->left ) {
ret.emplace_back( cur->val );
cur = cur->right;
} else {
mostright = cur->left;
while ( mostright->right && mostright->right != cur )
mostright = mostright->right;
if ( mostright->right == cur ) {
ret.emplace_back( cur->val );
mostright->right = nullptr;
cur = cur->right;
} else {
mostright->right = cur;
cur = cur->left;
}
}
}
return ret;
}
};
/*
時間:0ms,擊敗:100.00%
記憶體:8.1MB,擊敗:92.20%
*/