为了找到二叉搜索树中的节点 p 的中序后继,最直观的方法是中序遍历。由于只需要找到节点 p 的中序后继,因此不需要维护完整的中序遍历序列,只需要在中序遍历的过程中维护上一个访问的节点和当前访问的节点。如果上一个访问的节点是节点 p,则当前访问的节点即为节点 p 的中序后继。
如果节点 p 是最后被访问的节点,则不存在节点 p 的中序后继,返回 null。
[sol1-Python3]
1 2 3 4 5 6 7 8 9 10 11 12 13
classSolution: definorderSuccessor(self, root: 'TreeNode', p: 'TreeNode') -> 'TreeNode': st, pre, cur = [], None, root while st or cur: while cur: st.append(cur) cur = cur.left cur = st.pop() if pre == p: return cur pre = cur cur = cur.right returnNone
var inorderSuccessor = function(root, p) { const stack = []; let prev = null, curr = root; while (stack.length || curr) { while (curr) { stack.push(curr); curr = curr.left; } curr = stack.pop(); if (prev === p) { return curr; } prev = curr; curr = curr.right; } returnnull; };
[sol1-Golang]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
funcinorderSuccessor(root *TreeNode, p *TreeNode) *TreeNode { st := []*TreeNode{} var pre, cur *TreeNode = nil, root forlen(st) > 0 || cur != nil { for cur != nil { st = append(st, cur) cur = cur.Left } cur = st[len(st)-1] st = st[:len(st)-1] if pre == p { return cur } pre = cur cur = cur.Right } returnnil }
复杂度分析
时间复杂度:O(n),其中 n 是二叉搜索树的节点数。中序遍历最多需要访问二叉搜索树中的每个节点一次。
空间复杂度:O(n),其中 n 是二叉搜索树的节点数。空间复杂度取决于栈深度,平均情况是 O(\log n),最坏情况是 O(n)。
方法二:利用二叉搜索树的性质
二叉搜索树的一个性质是中序遍历序列单调递增,因此二叉搜索树中的节点 p 的中序后继满足以下条件:
中序后继的节点值大于 p 的节点值;
中序后继是节点值大于 p 的节点值的所有节点中节点值最小的一个节点。
利用二叉搜索树的性质,可以在不做中序遍历的情况下找到节点 p 的中序后继。
如果节点 p 的右子树不为空,则节点 p 的中序后继在其右子树中,在其右子树中定位到最左边的节点,即为节点 p 的中序后继。
如果 node 的节点值大于 p 的节点值,则 p 的中序后继可能是 node 或者在 node 的左子树中,因此用 node 更新答案,并将 node 移动到其左子节点继续遍历;
如果 node 的节点值小于或等于 p 的节点值,则 p 的中序后继可能在 node 的右子树中,因此将 node 移动到其右子节点继续遍历。
由于在遍历过程中,当且仅当 node 的节点值大于 p 的节点值的情况下,才会用 node 更新答案,因此当节点 p 有中序后继时一定可以找到中序后继,当节点 p 没有中序后继时答案一定为 null。
[sol2-Python3]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
classSolution: definorderSuccessor(self, root: 'TreeNode', p: 'TreeNode') -> 'TreeNode': successor = None if p.right: successor = p.right while successor.left: successor = successor.left return successor node = root while node: if node.val > p.val: successor = node node = node.left else: node = node.right return successor
var inorderSuccessor = function(root, p) { let successor = null; if (p.right) { successor = p.right; while (successor.left) { successor = successor.left; } return successor; } let node = root; while (node) { if (node.val > p.val) { successor = node; node = node.left; } else { node = node.right; } } return successor; };
funcinorderSuccessor(root *TreeNode, p *TreeNode) *TreeNode { var successor *TreeNode if p.Right != nil { successor = p.Right for successor.Left != nil { successor = successor.Left } return successor } node := root for node != nil { if node.Val > p.Val { successor = node node = node.Left } else { node = node.Right } } return successor }
复杂度分析
时间复杂度:O(n),其中 n 是二叉搜索树的节点数。遍历的节点数不超过二叉搜索树的高度,平均情况是 O(\log n),最坏情况是 O(n)。