145:删除二叉搜索树中的节点

LeetCode 450 https://leetcode.cn/problems/delete-node-in-a-bst/description/ 难度:中等 高频面试题汇总:https://www.yuweihung.com/posts/2025/lc-hot/ root 为空,代表未搜索到值为 key 的节点,返回空。 root.val>key,表示值为 key 的节点可能存在于 root 的左子树中,需要递归地在 root.left 调用 deleteNode,并返回 root。 root.val<key,表示值为 key 的节点可能存在于 root 的右子树中,需要递归地在 root.right 调用 deleteNode,并返回 root。 root.val=key,root 即为要删除的节点。此时要做的是删除 root,并将它的子树合并成一棵子树,保持有序性,并返回根节点。根据 root 的子树情况分成以下情况讨论: root 为叶子节点,没有子树。此时可以直接将它删除,即返回空。 root 只有左子树,没有右子树。此时可以将它的左子树作为新的子树,返回它的左子节点。 root 只有右子树,没有左子树。此时可以将它的右子树作为新的子树,返回它的右子节点。 root 有左右子树,这时可以将 root 的后继节点(比 root 大的最小节点,即它的右子树中的最小节点,记为 successor)作为新的根节点替代 root,并将 successor 从 root 的右子树中删除,使得在保持有序性的情况下合并左右子树。 简单证明,successor 位于 root 的右子树中,因此大于 root 的所有左子节点;successor 是 root 的右子树中的最小节点,因此小于 root 的右子树中的其他节点。以上两点保持了新子树的有序性。 在代码实现上,我们可以先寻找 successor,再删除它。successor 是 root 的右子树中的最小节点,可以先找到 root 的右子节点,再不停地往左子节点寻找,直到找到一个不存在左子节点的节点,这个节点即为 successor。然后递归地在 root.right 调用 deleteNode 来删除 successor。因为 successor 没有左子节点,因此这一步递归调用不会再次步入这一种情况。然后将 successor 更新为新的 root 并返回。 时间复杂度:O(n),其中 n 为 root 的节点个数。最差情况下,寻找和删除 successor 各需要遍历一次树。 空间复杂度:O(n),其中 n 为 root 的节点个数。递归的深度最深为 O(n)。 ...

七月 15, 2025 · Cassius

140:二叉搜索树的第k大节点

LCR 174 https://leetcode.cn/problems/er-cha-sou-suo-shu-de-di-kda-jie-dian-lcof/description/ 难度:简单 高频面试题汇总:https://www.yuweihung.com/posts/2025/lc-hot/ 二叉搜索树前序遍历为递增序列,而把前序遍历反过来可以得到递减序列。 如何把前序遍历反过来呢?为 “右、根、左” 顺序。 当访问到第 cnt 个节点,即可返回。 时间复杂度:O(n) 空间复杂度:O(n) ...

七月 15, 2025 · Cassius

137:另一个树的子树

LeetCode 572 https://leetcode.cn/problems/subtree-of-another-tree/description/ 难度:简单 高频面试题汇总:https://www.yuweihung.com/posts/2025/lc-hot/ 如果暴力匹配,时间复杂度是 O(n⋅min(n,m)),如何改进呢? 定义节点 node 的高度为 node 到其最深叶子的路径上的节点个数。特别地,叶子的高度为 1。设 subRoot 的高度为 hs。 设 node 为 root 中的节点。我们可以在匹配之前,先判断 node 的高度是否等于 hs,只有在相等时才做匹配。 这样做的时间复杂度是多少呢? 首先,对于 root 中的两个高度相同的节点 p 和 q(p  =q),不可能出现 p 是 q 的祖先,或者 q 是 p 的祖先。因为如果 p 是 q 的祖先,那么 p 的高度必然大于 q 的高度,反之亦然。 其次,对于 root 中的两个高度相同的节点 p 和 q(p != q),子树 p 和子树 q 没有任何交集。假如有交集,说明从 p 出发可以到达某个点 node,从 q 出发也可以到达 node,但这只有在 p 是 q 的祖先,或者 q 是 p 的祖先时才成立,与两个节点高度相同矛盾。 所以,root 中的所有与 hs 高度相同的节点,对应的子树两两不相交,这些子树的节点个数之和不超过 n,所以总的匹配次数也不会超过 n,下面代码中的 dfs 的时间复杂度为 O(n)。 时间复杂度:O(n+m),其中 n 是二叉树 root 的节点个数,m 是二叉树 subRoot 的节点个数。注意当 subRoot 的节点个数比 n 还要多时,dfs 并不会遍历 subRoot 中的所有节点。其中 O(m) 是计算 subRoot 树高的时间,如果限制 getHeight 递归访问的节点个数至多为 n,则可以做到 O(n) 的时间复杂度。 空间复杂度:O(n+m)。如果限制 getHeight 递归访问的节点个数至多为 n,则可以做到 O(n) 的(栈)空间复杂度。 ...

七月 15, 2025 · Cassius

135:二叉树的后序遍历

LeetCode 145 https://leetcode.cn/problems/binary-tree-postorder-traversal/description/ 难度:简单 高频面试题汇总:https://www.yuweihung.com/posts/2025/lc-hot/ 二叉树后序遍历。 时间复杂度:O(n),其中 n 是二叉搜索树的节点数。每一个节点恰好被遍历一次。 空间复杂度:O(n),为递归过程中栈的开销,平均情况下为 O(logn),最坏情况下树呈现链状,为 O(n)。 ...

七月 15, 2025 · Cassius

133:树的子结构

LCR 143 https://leetcode.cn/problems/shu-de-zi-jie-gou-lcof/description/ 难度:中等 高频面试题汇总:https://www.yuweihung.com/posts/2025/lc-hot/ 具有相同子结构的条件是: A、B 非空 dfs(A, B) 或 dfs(A->left, B) 或 dfs(A->right, B) 时间复杂度 O(MN): 其中 M,N 分别为树 A 和 树 B 的节点数量;先序遍历树 A 占用 O(M),每次调用 dfs(A, B) 判断占用 O(N)。 空间复杂度 O(M): 当树 A 和树 B 都退化为链表时,递归调用深度最大。当 M ≤ N 时,遍历树 A 与递归判断的总递归深度为 M;当 M > N 时,最差情况为遍历至树 A 的叶节点,此时总递归深度为 M。 ...

七月 15, 2025 · Cassius

130:二叉树展开为链表

LeetCode 114 https://leetcode.cn/problems/flatten-binary-tree-to-linked-list/description/ 难度:中等 高频面试题汇总:https://www.yuweihung.com/posts/2025/lc-hot/ 采用头插法构建链表,按照右子树 - 左子树 - 根的顺序 DFS 这棵树。DFS 的同时,记录当前链表的头节点为 head。一开始 head 是空节点。 具体来说: 如果当前节点为空,返回。 递归右子树。 递归左子树。 把 root.left 置为空。 头插法,把 root 插在 head 的前面,也就是 root.right=head。 现在 root 是链表的头节点,把 head 更新为 root。 时间复杂度:O(n),其中 n 是二叉树的节点个数。 空间复杂度:O(n)。递归需要 O(n) 的栈空间。 ...

七月 15, 2025 · Cassius

121:二叉搜索树与双向链表

LCR 155 https://leetcode.cn/problems/er-cha-sou-suo-shu-yu-shuang-xiang-lian-biao-lcof/ 难度:中等 高频面试题汇总:https://www.yuweihung.com/posts/2025/lc-hot/ 使用中序遍历遍历二叉树搜索树,定义变量 head,pre,当前节点 cur,cur->left = pre,pre->right = cur。最后 pre 指向最后一个节点,更新 head->left = pre,pre->right = head。 时间复杂度:O(n) 空间复杂度:O(n) ...

七月 15, 2025 · Cassius

119:二叉树的完全性检验

LeetCode 958 https://leetcode.cn/problems/check-completeness-of-a-binary-tree/description/ 难度:中等 高频面试题汇总:https://www.yuweihung.com/posts/2025/lc-hot/ 层序遍历二叉树。如果遍历到了一个非空节点之前遍历过空节点,就不是完全二叉树。 时间复杂度:O(N),其中 N 是树节点个数。 空间复杂度:O(N)。 ...

七月 15, 2025 · Cassius

103:二叉树的序列化与反序列化

LeetCode 297 https://leetcode.cn/problems/serialize-and-deserialize-binary-tree/description/ 难度:困难 高频面试题汇总:https://www.yuweihung.com/posts/2025/lc-hot/ 本题可以使用前序遍历或者层序遍历,这里使用层序遍历。 在序列化时需要注意空节点也需要保存。在反序列化时,为了分割字符串,使用了 stringstream。 getline(ss, token, ',') 序列化和反序列化的时空复杂度相同。 时间复杂度:O(n)。 空间复杂度:O(n)。 ...

七月 13, 2025 · Cassius

097:翻转二叉树

LeetCode 226 https://leetcode.cn/problems/invert-binary-tree/description/ 难度:简单 高频面试题汇总:https://www.yuweihung.com/posts/2025/lc-hot/ 递归调用 invertTree(root.left),获取到左子树翻转后的结果 left。 递归调用 invertTree(root.right),获取到右子树翻转后的结果 right。 交换左右儿子,即更新 root.left 为 right,更新 root.right 为 left。 返回 root。 递归边界:如果 root 是空节点,返回空。 时间复杂度:O(n),其中 n 为二叉树的节点个数。 空间复杂度:O(n)。最坏情况下,二叉树退化成一条链,递归需要 O(n) 的栈空间。 ...

七月 6, 2025 · Cassius