摘要:解法二迭代中序遍歷分析作者二叉搜索樹的中序后繼是中序遍歷中當前節點之后最小的節點。
給定一棵二叉搜索樹和其中的一個節點 p
,找到該節點在樹中的中序后繼。如果節點沒有中序后繼,請返回 null
。
節點 p
的后繼是值比 p.val
大的節點中鍵值最小的節點。
- 輸入:
root = [2,1,3]
,p = 1
- 輸出: 2 2 2
- 解釋: 這里 1 1 1 的中序后繼是 2 2 2 。請注意
p
和返回值都應是TreeNode
類型。
- 輸入:
root = [5, 3, 6, 2, 4, null, null, 1]
,p = 6
- 輸出:
null
- 解釋: 因為給出的節點沒有中序后繼,所以答案就返回
null
了。
- 來源: 力扣(LeetCode)
- 鏈接: https://leetcode-cn.com/problems/inorder-successor-in-bst
既然要求尋找給定節點的中序遍歷后繼節點,則自然地可以想到先獲得該二叉搜索樹的中序遍歷序列,然后找并返回給定節點在中序遍歷序列中后一個節點即可。
因此,下面的實現先通過一次中序遍歷得到二叉搜索樹的一個中序遍歷序列 self._nodes
,然后在其中找到節點 p
對應的索引,最后根據索引確定是否有后繼節點。
from typing import Optionalclass TreeNode: def __init__(self, val: int, left=None, right=None): self.val = val self.left = left self.right = rightclass Solution: def __init__(self): self._nodes = [] def _inorder(self, root: TreeNode): if root is None: return self._inorder(root.left) self._nodes.append(root) self._inorder(root.right) def initialize(self): self._nodes = [] def successor(self, root: TreeNode, p: TreeNode) -> Optional[TreeNode]: self._inorder(root) index = self._nodes.index(p) if index >= len(self._nodes) - 1: return else: return self._nodes[index + 1]def main(): node6 = TreeNode(1) node5 = TreeNode(4) node4 = TreeNode(2, left=node6) node3 = TreeNode(6) node2 = TreeNode(3, left=node4, right=node5) node1 = TreeNode(5, left=node2, right=node3) root = node1 sln = Solution() def print_successor(suc: TreeNode): if suc: print(suc.val) else: print(None) print_successor(sln.successor(root, node6)) # 2 sln.initialize() print_successor(sln.successor(root, node2)) # 4 sln.initialize() print_successor(sln.successor(root, node5)) # 5 sln.initialize() print_successor(sln.successor(root, node3)) # Noneif __name__ == "__main__": main()
細心的讀者可能已經發現了,在上述實現的測試代碼中,每調用一次尋找后繼節點的 successor()
方法之后,都調用了一次 initialize()
方法將對象的實例屬性 _nodes
清空,原因在于每次調用 successor()
時,該方法都會調用一次 _inorder()
方法,如果不這么做會導致 _nodes
實例屬性包含多組中序遍歷序列,從而產生意料之外的錯誤。
實際上,稍顯優雅的做法如下,即將調用 _inorder()
方法獲得給定二叉搜索樹中序序列的操作放在初始化方法 __init__()
中,而在 successor()
方法中僅保留獲取后繼節點的邏輯,這樣就不會導致 _nodes
實例屬性在 ElegantSolution
對象的生命周期內被追加多組中序遍歷序列了。
from typing import Optionalclass TreeNode: def __init__(self, val: int, left=None, right=None): self.val = val self.left = left self.right = rightclass ElegantSolution: def __init__(self, root: TreeNode): self._nodes = [] self._inorder(root) def _inorder(self, root: TreeNode): if root is None: return self._inorder(root.left) self._nodes.append(root) self._inorder(root.right) def successor(self, p: TreeNode) -> Optional[TreeNode]: index = self._nodes.index(p) if index >= len(self._nodes) - 1: return else: return self._nodes[index + 1]def print_successor(suc: TreeNode): if suc: print(suc.val) else: print(None)def main(): node6 = TreeNode(1) node5 = TreeNode(4) node4 = TreeNode(2, left=node6) node3 = TreeNode(6) node2 = TreeNode(3, left=node4, right=node5) node1 = TreeNode(5, left=node2, right=node3) root = node1 sln = ElegantSolution(root) print_successor(sln.successor(node6)) # 2 print_successor(sln.successor(node2)) # 4 print_successor(sln.successor(node5)) # 5 print_successor(sln.successor(node3)) # Noneif __name__ == "__main__": main()
_nodes
來保存所有節點。
- 作者: LeetCode
二叉搜索樹的中序后繼是中序遍歷中當前節點之后 val
最小的節點。
可以分成兩種情況來討論:
如果是下圖這種情況,即當前節點有右子節點,找到順序后繼很簡單,先找到當前節點的右孩子,然后再持續往左直到左孩子為空。
下面再來看一個復雜一點的情況,即當前節點無右子節點,這時候由于無法訪問父親節點,只能從根節點開始中序遍歷。中序遍歷通常由有遞歸和迭代的實現方式,這里用迭代的實現方式會更好一點。
直接在中序遍歷過程保存前一個訪問的節點,判斷前一個節點是否為 p
,如果是的話當前節點就是 p
節點的順序后繼。
中序遍歷方法的時間復雜度為 O ( h ) O(h) O(h) ,其中 h h h 為樹的高度。在第一種情況下也可以用中序遍歷的方法,但之前的方法更快一點。
from typing import Optionalclass TreeNode: def __init__(self, val: int, left=None, right=None): self.val = val self.left = left self.right = rightclass Solution: def inorder_successor(self, root: TreeNode, p: TreeNode) -> Optional[TreeNode]: if root is None or not isinstance(root, TreeNode): return if p.right: node = p.right while node.left: node = node.left return node stack, prev = [], float("-inf") cursor = root while True: if cursor: stack.append(cursor) cursor = cursor.left elif stack: node = stack.pop() if prev == p.val: return node prev = node.val cursor = node.right else: break returndef print_successor(suc: TreeNode): if suc: print(suc.val) else: print(None)def main(): node6 = TreeNode(1) node5 = TreeNode(4) node4 = TreeNode(2, left=node6) node3 = TreeNode(6) node2 = TreeNode(3, left=node4, right=node5) node1 = TreeNode(5, left=node2, right=node3) root = node1 sln = Solution() print_successor(sln.inorder_successor(root, node6)) # 2 print_successor(sln.inorder_successor(root, node2)) # 4 print_successor(sln.inorder_successor(root, node5)) # 5 print_successor(sln.inorder_successor(root, node3)) # Noneif __name__ == "__main__": main()
p
有右子節點,時間復雜度為 O ( h p ) O(h_p) O(hp?) ,其中 O ( h p ) O(h_p) O(hp?) 是節點 p
的高度。如果沒有右子節點,時間復雜度為 O ( H ) O(H) O(H),其中 h h h 為樹的高度;p
有右子節點,空間復雜度為 O ( 1 ) O(1) O(1) 。如果沒有右子節點,空間復雜度度為 O ( h ) O(h) O(h) 。實際上,上述迭代解法并沒有充分利用給定的是一棵二叉搜索樹這一個條件,如果利用這個條件,上述的迭代實現可以進一步優化如下:
from typing import Optionalclass TreeNode: def __init__(self, val: int, left=None, right=None): self.val = val self.left = left self.right = rightclass Solution: def inorder_successor(self, root: TreeNode, p: TreeNode) -> Optional[TreeNode]: if root is None or not isinstance(root, TreeNode): return if p.right: node = p.right while node.left: node = node.left return node successor = None while root: if root.val < p.val: root = root.right elif root.val > p.val: successor = root root = root.left else: break return successor
上述實現進一步將空間復雜度降低到了 O ( 1 ) O(1) O(1) 。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/124763.html
摘要:解法一中序遍歷分析由于給定了二叉搜索樹,因此首先考慮中序遍歷,使用示例,我們先來分別看一下二叉搜索樹和累加樹中序遍歷的結果二叉搜索樹二叉累加樹。這里還是使用示例,我們再來觀察一下二叉搜索樹和累加樹中序遍歷的結果二叉搜索樹二叉累加樹。 ...
摘要:也就是說,有個節點的平衡二叉搜索樹,它的高度是。以搜索操作為例,如果二叉搜索樹的高度為,則時間復雜度為。二叉搜索樹的高度的確很重要。樹集合,中的或者中的,是由高度平衡的二叉搜索樹實現的。 ...
摘要:小鹿題目二叉樹中序遍歷給定一個二叉樹,返回它的中序遍歷。通常遞歸的方法解決二叉樹的遍歷最方便不過,但是我還是喜歡增加點難度,用一般的迭代循環來實現。 Time:2019/4/25Title:Binary Tree Inorder TraversalDifficulty: MediumAuthor:小鹿 題目:Binary Tree Inorder Traversal(二叉樹中序遍歷...
閱讀 1644·2021-11-24 09:39
閱讀 3081·2021-11-22 15:24
閱讀 3090·2021-10-26 09:51
閱讀 3275·2021-10-19 11:46
閱讀 2890·2019-08-30 15:44
閱讀 2216·2019-08-29 15:30
閱讀 2536·2019-08-29 15:05
閱讀 772·2019-08-29 10:55