ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

面试题 04.06 后继者:二叉搜索树中序后继的二分查找算法详解(doocs/leetcode 题解)

面试题 04.06 后继者:二叉搜索树中序后继的二分查找算法详解(doocs/leetcode 题解) 示例工程教程【免费下载链接】leetcodeLeetCode solutions in any programming language | 多种编程语言实现 LeetCode、《剑指 Offer第 2 版》、《程序员面试金典第 6 版》题解项目地址https://gitcode.com/doocs/leetcode点击查看免费下载本文以 doocs/leetcode 仓库中《程序员面试金典》系列题目 04.06. Successor后继者 的官方题解为骨架系统讲解二叉搜索树BST中序后继节点的定义、朴素遍历解法与 O(h) 二分查找解法并基于仓库中的多语言实现给出可直接运行的代码与复杂度分析帮助你掌握面试中高频的 BST 有序性利用技巧。题目概述什么是中序后继题目要求设计一个算法找出二叉搜索树中指定节点的下一个节点即中序后继。如果指定节点没有对应的下一个节点则返回null。在二叉搜索树中中序遍历的结果是一个升序序列。所谓中序后继就是中序遍历序列中位于节点 $p$ 之后的下一个节点——即值上刚刚比 $p$ 大的那个节点。本题难度为中等Medium标签为树、深度优先搜索收录于 lcci程序员面试金典题集中题目编号为 04.06。示例分析示例 1输入root [2,1,3], p 12 / \ 1 3输出2分析对树[2,1,3]做中序遍历得到[1, 2, 3]节点1的下一个节点是2。示例 2输入root [5,3,6,2,4,null,null,1], p 65 / \ 3 6 / \ 2 4 / 1输出null分析中序遍历序列为[1, 2, 3, 4, 5, 6]节点6已经是中序序列的最后一个节点不存在后继因此返回null。题目完整描述见 README_EN.md 与 README.md。思路一朴素中序遍历O(n)最直接的想法是对整棵 BST 做一次完整的中序遍历在遍历过程中记录上一个访问的节点当上一个节点等于p时当前访问节点即为中序后继。def inorder_successor_naive(root, p): stack [] prev None cur root while stack or cur: while cur: stack.append(cur) cur cur.left cur stack.pop() if prev is p: return cur prev cur cur cur.right return None这种做法的正确性依赖 BST 中序遍历的升序性质但其时间与空间复杂度均为 $O(n)$$n$ 为节点总数。它没有利用 BST 的有序性对于高度为 $h$、节点总数为 $n$ 的树而言属于线性开销。思路二利用 BST 有序性的二分查找O(h)原题解的核心思路在于中序后继是所有大于 $p.val$ 的节点中值最小的那一个。这一观察将问题从遍历整棵树转化为沿路径定向搜索从而可以在 $O(h)$ 时间内完成且空间复杂度为 $O(1)$完全不需要父指针也不需要 Morris 线索遍历。后继节点的两条判定条件中序后继节点的值大于$p$ 的节点值中序后继是所有大于 $p$ 的节点中值最小的节点。搜索规则从根节点root出发维护一个候选答案ans循环执行若root.val p.val则root是 $p$ 的潜在中序后继将其记为ans然后转向左子树继续寻找更小的更大值即root root.left若root.val p.val则root及其左子树都不可能成为后继值不够大后继只可能存在于右子树即root root.right。循环终止后ans即为所求。若整个过程中从未出现root.val p.val的节点例如 $p$ 是整棵树中值最大的节点ans保持null正好对应没有后继的语义。仓库中的多语言实现doocs/leetcode 仓库在 lcci/04.06.Successor 目录下提供了 Python、Java、C、Go、TypeScript、JavaScript、Swift 七种语言的独立实现文件Solution.py、Solution.java、Solution.cpp、Solution.go、Solution.ts、Solution.js、Solution.swift算法逻辑完全一致只是语言语法不同。Python# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val x # self.left None # self.right None class Solution: def inorderSuccessor(self, root: TreeNode, p: TreeNode) - Optional[TreeNode]: ans None while root: if root.val p.val: ans root root root.left else: root root.right return ansJava/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val x; } * } */ class Solution { public TreeNode inorderSuccessor(TreeNode root, TreeNode p) { TreeNode ans null; while (root ! null) { if (root.val p.val) { ans root; root root.left; } else { root root.right; } } return ans; } }C/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */ class Solution { public: TreeNode* inorderSuccessor(TreeNode* root, TreeNode* p) { TreeNode* ans nullptr; while (root) { if (root-val p-val) { ans root; root root-left; } else { root root-right; } } return ans; } };Go/** * Definition for a binary tree node. * type TreeNode struct { * Val int * Left *TreeNode * Right *TreeNode * } */ func inorderSuccessor(root *TreeNode, p *TreeNode) (ans *TreeNode) { for root ! nil { if root.Val p.Val { ans root root root.Left } else { root root.Right } } return }TypeScript/** * Definition for a binary tree node. * class TreeNode { * val: number * left: TreeNode | null * right: TreeNode | null * constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) { * this.val (valundefined ? 0 : val) * this.left (leftundefined ? null : left) * this.right (rightundefined ? null : right) * } * } */ function inorderSuccessor(root: TreeNode | null, p: TreeNode | null): TreeNode | null { let ans: TreeNode | null null; while (root) { if (root.val p.val) { ans root; root root.left; } else { root root.right; } } return ans; }JavaScript/** * Definition for a binary tree node. * function TreeNode(val) { * this.val val; * this.left this.right null; * } */ /** * param {TreeNode} root * param {TreeNode} p * return {TreeNode} */ var inorderSuccessor function (root, p) { let ans null; while (root) { if (root.val p.val) { ans root; root root.left; } else { root root.right; } } return ans; };Swift/* class TreeNode { * var val: Int * var left: TreeNode? * var right: TreeNode? * * init(_ val: Int) { * self.val val * self.left nil * self.right nil * } * } */ class Solution { func inorderSuccessor(_ root: TreeNode?, _ p: TreeNode?) - TreeNode? { var current root var successor: TreeNode? nil while let node current { if node.val p!.val { successor node current node.left } else { current node.right } } return successor } }各实现文件可在 lcci/04.06.Successor/Solution.py、Solution.java、Solution.cpp、Solution.go、Solution.ts、Solution.js、Solution.swift 中查看完整源码。所有实现均与 README_EN.md 内嵌的题解代码一一对应可直接复制运行。算法正确性剖析该算法为什么是对的关键在于维护的候选答案ans始终是到目前为止遇到的所有大于p.val的节点中值最小的那个当root.val p.val时root是一个合法候选但它的左子树中可能存在更小但仍大于p.val的节点因此更新ans root后继续下探左子树当root.val p.val时root及其整棵左子树的值都不大于p.val可以全部剪枝只搜索右子树从根到叶子的每一条路径最多访问 $h$ 个节点其中 $h$ 是树的高度最终停在叶子的空子树上循环自然结束。以示例 2 为例p 6值为 6 的节点是全局最大值从根 5 开始5 6不成立转向右子树 66 6不成立转向右子树空循环结束ans始终为null正确返回null。复杂度与扩展讨论时间复杂度$O(h)$其中 $h$ 为二叉搜索树的高度。在理想平衡树中 $h O(\log n)$在退化链状树中 $h O(n)$。空间复杂度$O(1)$仅使用常数个指针变量ans与root优于需要显式栈或递归栈的中序遍历方案。延伸思考如果题目给出的是父指针版本如 LeetCode 的Node定义包含parent同样可以在 $O(h)$ 时间内通过有右子树则取右子树最左节点否则向上找第一个作为左孩子的祖先完成本题的对称问题中序前驱predecessor可用完全对称的规则求解当root.val p.val时记录候选并转向右子树否则转向左子树该二分查找思路同样适用于题目 面试题 04.06 收录页所标注的树、深度优先搜索两类考点可迁移到其他在有序结构中定位相邻元素的问题上。总结面试题 04.06 的核心考点在于发现并利用 BST 中序遍历的升序有序性中序后继 大于p的最小节点。据此可以在 $O(h)$ 时间、$O(1)$ 空间内完成查找代码仅需一个while循环与一个候选指针变量是典型的用数学观察简化实现的面试题。完整题解与七种语言实现均可在 lcci/04.06.Successor 目录下查阅。赞分享示例工程教程【免费下载链接】leetcodeLeetCode solutions in any programming language | 多种编程语言实现 LeetCode、《剑指 Offer第 2 版》、《程序员面试金典第 6 版》题解项目地址https://gitcode.com/doocs/leetcode点击查看免费下载相关推荐剑指 Offer 04.06 后继者Successor LCCI二叉搜索树中序后继的二分搜索解法全解剑指 Offer 04.06 后继者Successor LCCI二叉搜索树中序后继的二分搜索解法全解 本文围绕《程序员面试金典第 6 版》中的面试题示例工程教程二叉搜索树中序后继节点算法解析二叉搜索树中序后继节点算法解析 问题描述 在二叉搜索树 BST 中给定一个节点我们需要找到它的中序遍历顺序下的后继节点。中序遍历顺序是指按照左子树 根节点示例工程教程doocs/leetcode 题解精讲面试题 04.09 二叉搜索树序列BST Sequences——递归交织子序列算法详解doocs/leetcode 题解精讲面试题 04.09 二叉搜索树序列BST Sequences——递归交织子序列算法详解 本篇技术指南围绕 doocs示例工程教程上一篇高性能Windows系统优化工具架构解析与深度清理技术实现下一篇Zotero中文文献管理终极方案Jasminum元数据自动抓取完整指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表