[LeetCode] 510. Inorder Successor in BST II 二叉搜索樹中的中序后繼節點之二


 

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

The successor of a node p is the node with the smallest key greater than p.val.

You will have direct access to the node but not to the root of the tree. Each node will have a reference to its parent node.

 

Example 1:

Input: 
root = {"$id":"1","left":{"$id":"2","left":null,"parent":{"$ref":"1"},"right":null,"val":1},"parent":null,"right":{"$id":"3","left":null,"parent":{"$ref":"1"},"right":null,"val":3},"val":2}
p = 1 Output: 2 Explanation: 1's in-order successor node is 2. Note that both p and the return value is of Node type. 

Example 2:

Input: 
root = {"$id":"1","left":{"$id":"2","left":{"$id":"3","left":{"$id":"4","left":null,"parent":{"$ref":"3"},"right":null,"val":1},"parent":{"$ref":"2"},"right":null,"val":2},"parent":{"$ref":"1"},"right":{"$id":"5","left":null,"parent":{"$ref":"2"},"right":null,"val":4},"val":3},"parent":null,"right":{"$id":"6","left":null,"parent":{"$ref":"1"},"right":null,"val":6},"val":5}
p = 6 Output: null Explanation: There is no in-order successor of the current node, so the answer is null. 

Example 3:

Input: 
root = {"$id":"1","left":{"$id":"2","left":{"$id":"3","left":{"$id":"4","left":null,"parent":{"$ref":"3"},"right":null,"val":2},"parent":{"$ref":"2"},"right":{"$id":"5","left":null,"parent":{"$ref":"3"},"right":null,"val":4},"val":3},"parent":{"$ref":"1"},"right":{"$id":"6","left":null,"parent":{"$ref":"2"},"right":{"$id":"7","left":{"$id":"8","left":null,"parent":{"$ref":"7"},"right":null,"val":9},"parent":{"$ref":"6"},"right":null,"val":13},"val":7},"val":6},"parent":null,"right":{"$id":"9","left":{"$id":"10","left":null,"parent":{"$ref":"9"},"right":null,"val":17},"parent":{"$ref":"1"},"right":{"$id":"11","left":null,"parent":{"$ref":"9"},"right":null,"val":20},"val":18},"val":15}
p = 15 Output: 17 

Example 4:

Input: 
root = {"$id":"1","left":{"$id":"2","left":{"$id":"3","left":{"$id":"4","left":null,"parent":{"$ref":"3"},"right":null,"val":2},"parent":{"$ref":"2"},"right":{"$id":"5","left":null,"parent":{"$ref":"3"},"right":null,"val":4},"val":3},"parent":{"$ref":"1"},"right":{"$id":"6","left":null,"parent":{"$ref":"2"},"right":{"$id":"7","left":{"$id":"8","left":null,"parent":{"$ref":"7"},"right":null,"val":9},"parent":{"$ref":"6"},"right":null,"val":13},"val":7},"val":6},"parent":null,"right":{"$id":"9","left":{"$id":"10","left":null,"parent":{"$ref":"9"},"right":null,"val":17},"parent":{"$ref":"1"},"right":{"$id":"11","left":null,"parent":{"$ref":"9"},"right":null,"val":20},"val":18},"val":15}
p = 13 Output: 15 

 

Note:

  1. If the given node has no in-order successor in the tree, return null.
  2. It's guaranteed that the values of the tree are unique.
  3. Remember that we are using the Node type instead of TreeNode type so their string representation are different.

 

Follow up:

Could you solve it without looking up any of the node's values?

 

這道題是之前的那道 Inorder Successor in BST 的后續,之前那道題給了我們樹的根結點,而這道題並沒有確定給我們根結點,只是給了樹的任意一個結點,然后讓求給定結點的中序后繼結點。這道題比較好的一點就是例子給的比較詳盡,基本覆蓋到了大部分的情況,包括一些很 tricky 的情況。首先來看例子1,結點1的中序后繼結點是2,因為中序遍歷的順序是左-根-右。還是例子1,結點2的中序后續結點是3,這樣我們就知道中序后續結點可以是其父結點或者右子結點。再看例子2,結點6的中序后續結點是空,因為其已經是中序遍歷的最后一個結點了,所以沒有后續結點。例子3比較 tricky,結點 15 的中序后續結點不是其右子結點,而是其右子結點的左子結點 17,這樣才符合左-根-右的順序。例子4同樣 tricky,結點 13 的中序后繼結點並不是其親生父結點,而是其祖爺爺結點 15。

好,看完了這四個例子,我們應該心里有些數了吧。后繼結點出現的位置大致可以分為兩類,一類是在子孫結點中,另一類是在祖先結點中。仔細觀察例子不難發現,當某個結點存在右子結點時,其中序后繼結點就在子孫結點中,反之則在祖先結點中。這樣我們就可以分別來處理,當右子結點存在時,我們需要找到右子結點的最左子結點,這個不難,就用個 while 循環就行了。當右子結點不存在,我們就要找到第一個比其值大的祖先結點,也是用個 while 循環去找即可,參見代碼如下:

 

解法一:

class Solution {
public:
    Node* inorderSuccessor(Node* node) {
        if (!node) return nullptr;
        Node *res = nullptr;
        if (node->right) {
            res = node->right;
            while (res && res->left) res = res->left;
        } else {
            res = node->parent;
            while (res && res->val < node->val) res = res->parent;
        }
        return res;
    }
};

 

本題的 Follow up 讓我們不要訪問結點值,那么上面的解法就不行了。因為當 node 沒有右子結點時,我們沒法通過比較結點值來找到第一個大於 node 的祖先結點。雖然不能比較結點值了,我們還是可以通過 node 相對於其 parent 的位置來判斷,當 node 是其 parent 的左子結點時,我們知道此時 parent 的結點值一定大於 node,因為這是二叉搜索樹的性質。若 node 是其 parent 的右子結點時,則將 node 賦值為其 parent,繼續向上找,直到其 parent 結點不存在了,此時說明不存在大於 node 值的祖先結點,這說明 node 是 BST 的最后一個結點了,沒有后繼結點,直接返回 nullptr 即可,參見代碼如下:

 

解法二:

class Solution {
public:
    Node* inorderSuccessor(Node* node) {
        if (!node) return nullptr;
        if (node->right) {
            node = node->right;
            while (node && node->left) node = node->left;
            return node;
        }
        while (node) {
            if (!node->parent) return nullptr;
            if (node == node->parent->left) return node->parent;
            node = node->parent;
        }
        return node;
    }
};

 

Github 同步地址:

https://github.com/grandyang/leetcode/issues/510

 

類似題目:

Inorder Successor in BST

 

參考資料:

https://leetcode.com/problems/inorder-successor-in-bst-ii/

https://leetcode.com/problems/inorder-successor-in-bst-ii/discuss/231587/Java-find-in-parents-or-find-in-descendents

https://leetcode.com/problems/inorder-successor-in-bst-ii/discuss/234295/Java-easy-understanding-well-explained-solution

 

LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM