🚩传送门:牛客题目

题目

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。

为了让您更好地理解问题,以下面的二叉搜索树为例:
[NC]52. 二叉搜索树与双向链表 - 图1
我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对于双向循环链表,第一个节点的前驱是最后一个节点,最后一个节点的后继是第一个节点。

下图展示了上面的二叉搜索树转化成的链表。“head” 表示指向链表中有最小元素的节点。
[NC]52. 二叉搜索树与双向链表 - 图2
特别地,我们希望可以就地完成转换操作。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中的第一个节点的指针。

要求:空间复杂度[NC]52. 二叉搜索树与双向链表 - 图3(即在原树上操作),时间复杂度 [NC]52. 二叉搜索树与双向链表 - 图4

示例 1:

输入:root = [4,2,5,1,3] 输出:[1,2,3,4,5] 解释:下图显示了转化后的二叉搜索树,实线表示后继关系,虚线表示前驱关系。

解题思路:递归中序遍历

本文解法基于性质:二叉搜索树的中序遍历为 递增序列

将 二叉搜索树 转换成一个 “排序的循环双向链表” ,其中包含三个要素:

  1. 排序: 节点应从小到大排序,因此应使用 中序遍历 “从小到大”访问树的节点。
  2. 双向: 在构建相邻节点的引用关系时,设前驱节点 _pre_当前节点 _cur_

    这样可以利用_pre.right = cur__cur.left = pre_ 完成双向的构建

  3. 循环: 设链表头节点 _head_,尾结点_tail_

    完成双向构建后,将head.left = tailtail.right = head 头结点:当遇到第一个结点,即head未初始化时,应当将当前结点置为头结点 尾结点:当 DFS 中序遍历递归结束时,pre指向的就是尾结点

🚩主要就是利用前驱节点 _pre_当前节点 _cur_依靠中序遍历,完成双向设置。
[NC]52. 二叉搜索树与双向链表 - 图5

复杂度分析

时间复杂度:[NC]52. 二叉搜索树与双向链表 - 图6,其中 [NC]52. 二叉搜索树与双向链表 - 图7 为二叉搜索树结点数 。

空间复杂度:[NC]52. 二叉搜索树与双向链表 - 图8

我的代码

  1. public class Solution {
  2. TreeNode Head;
  3. TreeNode pre;
  4. public void DFS(TreeNode cur){
  5. // 空指针返回
  6. if(cur==null) return;
  7. // 指针非空递归左子树
  8. DFS(cur.left);
  9. // 当前结点非空,若Head没初始化说明是初始态,当前结点应置为头结点
  10. if(Head==null) Head=cur;
  11. else{
  12. // 此时说明当前是中间态
  13. cur.left=pre;
  14. pre.right=cur;
  15. }
  16. pre=cur;
  17. DFS(cur.right);
  18. }
  19. public TreeNode Convert(TreeNode pRootOfTree) {
  20. DFS(pRootOfTree);
  21. // 如果不是循环双向链表就取消这一语句块
  22. {
  23. Head.left=pre;
  24. pre.right=Head;
  25. }
  26. return Head;
  27. }
  28. }