🚩传送门:牛客题目
题目
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
为了让您更好地理解问题,以下面的二叉搜索树为例:
我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对于双向循环链表,第一个节点的前驱是最后一个节点,最后一个节点的后继是第一个节点。
下图展示了上面的二叉搜索树转化成的链表。“head”
表示指向链表中有最小元素的节点。
特别地,我们希望可以就地完成转换操作。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中的第一个节点的指针。
要求:空间复杂度(即在原树上操作),时间复杂度
示例 1:
输入:root = [4,2,5,1,3] 输出:[1,2,3,4,5] 解释:下图显示了转化后的二叉搜索树,实线表示后继关系,虚线表示前驱关系。
解题思路:递归中序遍历
本文解法基于性质:二叉搜索树的中序遍历为 递增序列 。
将 二叉搜索树 转换成一个 “排序的循环双向链表” ,其中包含三个要素:
- 排序: 节点应从小到大排序,因此应使用 中序遍历 “从小到大”访问树的节点。
双向: 在构建相邻节点的引用关系时,设前驱节点
_pre_
和当前节点_cur_
这样可以利用
_pre.right = cur_
,_cur.left = pre_
完成双向的构建循环: 设链表头节点
_head_
,尾结点_tail_
。完成双向构建后,将
head.left = tail
,tail.right = head
头结点:当遇到第一个结点,即head
未初始化时,应当将当前结点置为头结点 尾结点:当 DFS 中序遍历递归结束时,pre
指向的就是尾结点
🚩主要就是利用前驱节点 _pre_
和当前节点 _cur_
,依靠中序遍历,完成双向设置。
复杂度分析
时间复杂度:,其中
为二叉搜索树结点数 。
空间复杂度:
我的代码
public class Solution {
TreeNode Head;
TreeNode pre;
public void DFS(TreeNode cur){
// 空指针返回
if(cur==null) return;
// 指针非空递归左子树
DFS(cur.left);
// 当前结点非空,若Head没初始化说明是初始态,当前结点应置为头结点
if(Head==null) Head=cur;
else{
// 此时说明当前是中间态
cur.left=pre;
pre.right=cur;
}
pre=cur;
DFS(cur.right);
}
public TreeNode Convert(TreeNode pRootOfTree) {
DFS(pRootOfTree);
// 如果不是循环双向链表就取消这一语句块
{
Head.left=pre;
pre.right=Head;
}
return Head;
}
}