LeetCode 面试题 17.12. BiNode
题目描述

题意分析
将二叉搜索树原地改成按节点值升序排列的单向右链:复用原节点,所有左指针置空,右指针指向排序后的下一节点,返回链头。二叉搜索树的中序遍历恰好给出所需顺序。
解法:中序遍历 + 原地右链
核心思路
[!blue]
使用显式栈执行中序遍历:游标
cur沿左链不断压栈,无法再向左时弹出一个节点,这就是尚未访问的最小节点。它的左子树已经处理完,接下来才轮到它自身和右子树。用
head记录首个访问节点,prev记录已访问序列的尾节点。每次弹出node,先清空其左指针;若它是首节点就设置head,否则令prev.right = node,把它接到已有前缀后面,再更新prev。由中序顺序保证,每次追加后已连接前缀仍然有序。原地改链接不会丢掉未访问部分。清空
node.left时,左子树已经全部访问;修改的是前驱prev的右指针,当前node的原右子树入口仍未改变,可以继续令cur = node.right。前驱原右子树的搜索也已经由此前的游标和栈接管,不再依赖被改写的前驱链接。每个节点最终都作为当前节点清空左指针,并在下一节点到来时连接右后继。最后访问的是最大节点,它原本就没有右子树,因此链尾自然为空,不需要额外创建节点或哨兵。
解题步骤
- 初始化空栈,
cur = root,head、prev为空。- 只要游标非空就沿左链压栈;到达空位置后弹出下一个中序节点。
- 清空当前节点左指针,设置链头或连接前驱,然后将
prev移到当前节点。- 让游标进入当前节点的原右子树,重复以上过程,直到游标和栈都为空,返回
head。空树不会进入循环,直接返回空。
代码实现
class Solution {
public TreeNode convertBiNode(TreeNode root) {
Deque<TreeNode> stack = new ArrayDeque<>();
TreeNode cur = root;
TreeNode head = null;
TreeNode prev = null;
while (cur != null || !stack.isEmpty()) {
while (cur != null) {
stack.push(cur);
cur = cur.left;
}
TreeNode node = stack.pop();
// 左子树已完成,清空左指针后接入已访问前缀。
node.left = null;
if (prev == null) {
head = node;
} else {
prev.right = node;
}
prev = node;
// 读取当前节点的原右子树入口,后续继续中序遍历。
cur = node.right;
}
return head;
}
}
func convertBiNode(root *TreeNode) *TreeNode {
var stack []*TreeNode
cur := root
var head *TreeNode
var prev *TreeNode
for cur != nil || len(stack) > 0 {
for cur != nil {
stack = append(stack, cur)
cur = cur.Left
}
node := stack[len(stack)-1]
stack = stack[:len(stack)-1]
// 左子树已完成,清空左指针后接入已访问前缀。
node.Left = nil
if prev == nil {
head = node
} else {
prev.Right = node
}
prev = node
// 读取当前节点的原右子树入口,后续继续中序遍历。
cur = node.Right
}
return head
}
复杂度分析
- 时间复杂度:$O(n)$。每个节点入栈、出栈各一次,重连指针只需常数时间。
- 空间复杂度:$O(h)$。显式栈深度由树高
h决定,最坏链状树为 $O(n)$;结果复用原节点。
关键点总结
[!green]
- 中序访问顺序决定链表顺序,
head和prev分别保存已连接前缀的头尾。- 左子树处理完才清空左指针,当前右子树入口读取后继续遍历。
- 必须先用旧
prev连接当前节点,再更新prev,不能把前驱和当前节点混成同一个对象。
易错点总结
[!yellow]
- 还没沿左链下降就清空左指针,会切断未访问子树。
- 先令
prev = node再写prev.right = node,会把当前节点连向自身。- 忘记更新
prev,后续节点无法依次接入完整右链。- 返回原根可能漏掉更小节点,必须返回中序首节点
head。- 只检查游标是否为空就结束,会丢掉栈中尚待处理的祖先。
相似题目
| 题目 | 难度 | 关联与区别 |
|---|---|---|
| 114. 二叉树展开为链表 | 中等 | 同样原地连成链,本题按BST中序成为递增右链,原题按前序展开普通二叉树。 |
| 426. 将二叉搜索树转化为排序的双向链表 | 中等 | 同样按BST中序重连节点,原题连接为循环双向链表,本题只保留向右的单链。 |
转载与许可
许可
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!