@author: sdubrz
@date: 8/3/2020 4:22:22 PM
难度: 中等
考察内容: 二叉搜索树, 链表
@e-mail: lwyz521604#163.com
题目来自《剑指offer》 电子工业出版社,图片来自LeetCode
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
为了让您更好地理解问题,以下面的二叉搜索树为例:
我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对于双向循环链表,第一个节点的前驱是最后一个节点,最后一个节点的后继是第一个节点。
下图展示了上面的二叉搜索树转化成的链表。“head” 表示指向链表中有最小元素的节点。
特别地,我们希望可以就地完成转换操作。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中的第一个节点的指针。
解法
一种比较容易理解的思路是使用递归。在得到左子树的链表与右子树的链表之后将其与根节点合并。下面是具体的Java程序实现:
/*
// Definition for a Node.
class Node {
public int val;
public Node left;
public Node right;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val,Node _left,Node _right) {
val = _val;
left = _left;
right = _right;
}
};
*/
class Solution {
public Node treeToDoublyList(Node root) {
if(root==null) {
return null;
}
//System.out.println("根节点为 "+root.val);
if(root.left==null && root.right==null) {
root.left = root;
root.right = root;
return root;
}
return treeToDoublyList0(root);
}
public Node treeToDoublyList0(Node root) {
if(root==null) {
return null;
}
//System.out.println("根节点为 "+root.val);
if(root.left==null && root.right==null) {
return root;
}
Node leftHead = null;
Node rightHead = null;
if(root.left!=null) {
leftHead = treeToDoublyList(root.left);
}
if(root.right!=null) {
rightHead = treeToDoublyList(root.right);
}
root.left = null;
root.right = null;
Node head = root;
if(leftHead!=null) {
if(leftHead.left!=null) { // 不是叶子节点
Node tempNode = leftHead.left;
leftHead.left = root;
root.left = tempNode;
root.right = leftHead;
tempNode.right = root;
}else { // 叶子节点
leftHead.left = root;
leftHead.right = root;
root.left = leftHead;
root.right = leftHead;
}
head = leftHead;
}
// System.out.println("根节点为 "+root.val+" 时,加上左子树的结果");
// printList(head);
if(rightHead!=null) {
if(head.right==null) { // 左子树为空
if(rightHead.left!=null) { // 不是叶子节点
Node tempNode = rightHead.left;
rightHead.left = head;
head.right = rightHead;
head.left = tempNode;
tempNode.right = head;
}else { // 是叶子节点
head.right = rightHead;
head.left = rightHead;
rightHead.left = head;
rightHead.right = head;
}
}else { // 左子树不为空
if(rightHead.left!=null) { // 不是叶子节点
Node tempNode1 = head.left;
Node tempNode2 = rightHead.left;
head.left = tempNode2;
rightHead.left = tempNode1;
tempNode1.right = rightHead;
tempNode2.right = head;
//System.out.println("RightHead = "+rightHead.val);
}else { // 是叶子节点
Node tempNode = head.left;
head.left = rightHead;
rightHead.right = head;
rightHead.left = tempNode;
tempNode.right = rightHead;
//System.out.println("rightHead = "+rightHead.val);
}
}
}
// System.out.println("根节点为 "+root.val+" 时,加上右子树的结果");
// printList(head);
return head;
}
}
下面是在LeetCode系统中提交的结果
执行结果:通过 显示详情
执行用时:1 ms, 在所有 Java 提交中击败了18.34%的用户
内存消耗:39.6 MB, 在所有 Java 提交中击败了11.89%的用户
这个方法效率不高,其实中序遍历是更好的实现思路。