1. 程式人生 > 其它 >Java常用類庫:Class Math

Java常用類庫:Class Math

技術標籤: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
    100Node.val100

進階: 遞迴演算法很簡單,你可以通過迭代演算法完成嗎?


題解:

二叉樹中序遍歷順序:左子樹、根節點、右子樹。

法一:

遞迴。

先遞迴左子樹,將根節點值加入答案,在遞迴右子樹。

時間複雜度: 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

    1. 如果 mostrightright 指標指向空,讓其指向 curcur 向左移動(cur = cur.left
    2. 如果 mostrightright 指標指向 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%
*/