1. 程式人生 > >[LeetCode] Inorder Successor in BST 二叉搜尋樹中的中序後繼節點

[LeetCode] Inorder Successor in BST 二叉搜尋樹中的中序後繼節點

Given a binary search tree and a node in it, find the in-order successor of that node in the BST.

Note: If the given node has no in-order successor in the tree, return null.

這道題讓我們求二叉搜尋樹的某個節點的中序後繼節點,那麼我們根據BST的性質知道其中序遍歷的結果是有序的, 是我最先用的方法是用迭代的中序遍歷方法,然後用一個bool型的變數b,初始化為false,我們進行中序遍歷,對於遍歷到的節點,我們首先看如果此時b已經為true,說明之前遍歷到了p,那麼此時我們返回當前節點,如果b仍為false,我們看遍歷到的節點和p是否相同,如果相同,我們此時將b賦為true,那麼下一個遍歷到的節點就能返回了,參見程式碼如下:

解法一:

class Solution {
public:
    TreeNode* inorderSuccessor(TreeNode* root, TreeNode* p) {
        stack<TreeNode*> s;
        bool b = false;
        TreeNode *t = root;
        while (t || !s.empty()) {
            while (t) {
                s.push(t);
                t = t->left;
            }
            t 
= s.top(); s.pop(); if (b) return t; if (t == p) b = true; t = t->right; } return NULL; } };

下面這種方法是用的中序遍歷的遞迴寫法,我們需要兩個全域性變數pre和suc,分別用來記錄祖先節點和後繼節點,我們初始化將他們都賦為NULL,然後在進行遞迴中序遍歷時,對於遍歷到的節點,我們首先看pre和p是否相同,如果相同,則suc賦為當前節點,然後將pre賦為root,那麼在遍歷下一個節點時,pre就起到記錄上一個節點的作用,參見程式碼如下:

解法二:

class Solution {
public:
    TreeNode* inorderSuccessor(TreeNode* root, TreeNode* p) {
        if (!p) return NULL;
        inorder(root, p);
        return suc;
    }
    void inorder(TreeNode *root, TreeNode *p) {
        if (!root) return;
        inorder(root->left, p);
        if (pre == p) suc = root;
        pre = root;
        inorder(root->right, p);
    }
private:
    TreeNode *pre = NULL, *suc = NULL;
};

再來看一種更簡單的方法,這種方法充分地利用到了BST的性質,我們首先看根節點值和p節點值的大小,如果根節點值大,說明p節點肯定在左子樹中,那麼此時我們先將res賦為root,然後root移到其左子節點,迴圈的條件是root存在,我們再比較此時root值和p節點值的大小,如果還是root值大,我們重複上面的操作,如果p節點值,那麼我們將root移到其右子節點,這樣當root為空時,res指向的就是p的後繼節點,參見程式碼如下:

解法三:

class Solution {
public:
    TreeNode* inorderSuccessor(TreeNode* root, TreeNode* p) {
        TreeNode *res = NULL;
        while (root) {
            if (root->val > p->val) {
                res = root;
                root = root->left;
            } else root = root->right;
        }
        return res;
    }
};

上面那種方法也可以寫成遞迴形式,寫法也比較簡潔,但是需要把思路理清,當根節點值小於等於p節點值,說明p的後繼節點一定在右子樹中,所以對右子節點遞迴呼叫此函式,如果根節點值大於p節點值,那麼有可能根節點就是p的後繼節點,或者左子樹中的某個節點是p的後繼節點,所以先對左子節點遞迴呼叫此函式,如果返回空,說明根節點是後繼節點,返回即可,如果不為空,則將那個節點返回,參見程式碼如下:

解法四:

class Solution {
public:
    TreeNode* inorderSuccessor(TreeNode* root, TreeNode* p) {
        if (!root) return NULL;
        if (root->val <= p->val) {
            return inorderSuccessor(root->right, p);
        } else {
            TreeNode *left = inorderSuccessor(root->left, p);
            return left ? left : root;
        }
    }
};

類似題目:

參考資料: