Skip to content
本页目录

36-二叉搜索树与双向链表

题目描述

https://leetcode.cn/problems/er-cha-sou-suo-shu-yu-shuang-xiang-lian-biao-lcof

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

为了让您更好地理解问题,以下面的二叉搜索树为例:

我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对于双向循环链表,第一个节点的前驱是最后一个节点,最后一个节点的后继是第一个节点。

下图展示了上面的二叉搜索树转化成的链表。“head” 表示指向链表中有最小元素的节点。

特别地,我们希望可以就地完成转换操作。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中的第一个节点的指针。

注意:本题与主站 426 题相同:https://leetcode.cn/problems/convert-binary-search-tree-to-sorted-doubly-linked-list/

注意:此题对比原题有改动。

思路分析

如果树有节点,则拍扁的时候,将子节点插入上面的两个节点中间

基本思路:中序遍历: 左根右 ,最左边的就是 head

实现代码

csharp
/*
// Definition for a Node.
public class Node {
    public int val;
    public Node left;
    public Node right;

    public Node() {}

    public Node(int _val) {
        val = _val;
        left = null;
        right = null;
    }

    public Node(int _val,Node _left,Node _right) {
        val = _val;
        left = _left;
        right = _right;
    }
}
*/

public class Solution {
    
    private Node pre;  //前一个节点
    private Node head; //头节点

    private void dfs(Node cur){
        if(cur == null){
            return;
        }
        //往左递归,就是最小的那个
        dfs(cur.left);
        //第一次满足条件, head 为空,当前就是 head
        if(head == null){
            head = cur;
        }
        if(pre != null){
            pre.right = cur;
            cur.left = pre;
        }
        pre = cur;
        dfs(cur.right);
    }


    public Node TreeToDoublyList(Node root) {
        //边界值
        if(root == null){
            return null;
        }
        dfs(root);
        //题目要求
        head.left = pre;
        pre.right = head;
        return head;
    }
}

错误代码参考

出错示例:[28,-98,67,null,-89,62,null,-97,-25,null,64,null,null,-72,-9,null,null,-88,-41,null,-7,null,-78,-53,null,null,2,-85,-77,-69,-42,-1]

        28
      /   \
    -98    67
       \
        -89
csharp

public class Solution {

    private Node head = null;

    private Node dfs(Node root){
        if(root == null){
            return null;
        }
        Node cur = dfs(root.left);
        Console.Write("{0} ",root.val);
        //头节点
        if(head == null){
            head = root;
        }
        if(cur != null){
            //找出他最后一个节点(此处不对 cur.right 第一次遍历的时候,就可能有值了,应该是他自己)
            //比如上图遍历到 98 的时候他的最右节点应该是自己,但是这里却返回了 -89 他之前本来就有的最右节点,所以出错了。
            // 836
            cur.right = root;            
            root.left = cur;
        }
        //注意:这里其实dfs的时候不需要返回左边的节点来处理,直接用 root 作为当前节点,参考下面复习代码

        Node temp = dfs(root.right);
        if(temp != null){
            temp.left = root;
        }
        return root;
    }

    public Node TreeToDoublyList(Node root) {
        if(root == null){
            return null;
        }
        dfs(root);
        //链接首尾
        Node cur = root;
        while(cur.right != null){
            cur = cur.right;
        }
        cur.right = head;
        head.left = cur;
        return head;
    }
}

复习:20220508

csharp
public class Solution {
    private Node head;
    private Node pre;
    private void dfs(Node root){
        if(root == null){
            return;
        }
        dfs(root.left);
        //处理头结点     
        if(head == null){ //如果头指针为空,说明找到了最左边的子节点,设置为头指针
            head = root;
        }
        else{ //头指针找到了后,必然会开始设置前驱节点,所以当 head != null 的时候,pre 必然有值,所以开始设置前驱节点
            pre.right = root;
            root.left = pre;
        }
        //设置 pre 下个循环有用
        pre = root;
        dfs(root.right);
    }

    public Node TreeToDoublyList(Node root) {
        if(root == null){
            return null;
        }
        dfs(root);
        // 最后按照题意组合收尾相连,此时 pre 就是最后一个指针
        pre.right = head;
        head.left = pre;
        return head;
    }
}

Morris遍历

csharp
public class Solution {
    public Node TreeToDoublyList(Node root){
        if(root == null){
            return null;
        }
        Node cur = root; 
        Node mostRight = null; //morris 的最右指针
        Node head = root; //头指针,最后会一直指向到最左边
        Node pre = null; //前一个指针

        //先找出最左指针
        while(head.left != null){
            head = head.left;
        }

        while(cur != null){
            mostRight = cur.left;
            if(mostRight != null){
                while(mostRight.right != null && mostRight.right != cur){
                    mostRight = mostRight.right;
                }

                if(mostRight.right == null){ //建立连接
                    mostRight.right = cur;
                    cur = cur.left;
                    continue;
                }
            }

            Node now = cur; //记录遍历过的节点
            cur = cur.right; //必须先将cur指向下一个节点
            if(pre != null){
                now.left = pre;
                pre.right = now;
            }
            pre = now;
        
        }
        //最后收尾相连
        pre.right = head;
        head.left = pre;
        return head;

    }
}

复习:20220611

csharp
public class Solution {

    private Node pre = null;
    private Node head = null;

    private void dfs(Node root){
        if(root == null){
            return;
        }
        dfs(root.left);
        if(head == null){
            head = root;
        }
        if(pre != null){
            root.left = pre;
            pre.right = root;
        }
        pre = root;
        dfs(root.right);
    }

    public Node TreeToDoublyList(Node root) {
        if(root == null){
            return null;
        }
        dfs(root);
        head.left = pre;
        pre.right = head;
        return head;
    }
}

Released under the MIT License.