输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
这道题仔细看,就会发现是中序遍历+改变指针指向。
但我就是那么菜,明明知道了总体思路还是不会编,最后看了讨论区中的高票回答,豁然开朗。
中序遍历分为递归和非递归。
非递归遍历时,由于需要更改指针,所以需要增加一个节点记录上一次遍历到的节点。
递归遍历时,就是先递归求出左子树的结果,返回左子树的双向链表的第一个节点,然后我们对这个双向链表遍历,得到它的最后一个节点,然后加上root,然后递归求右子树的结果,即右子树的双向链表的第一个节点,root加上这个节点即可。
方法一:非递归遍历
import java.util.*;
public class Solution {
public TreeNode Convert(TreeNode root) {
if(root == null) return null;
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root , pre = null , head = null;
boolean isFirst = true;
while(cur != null || !stack.isEmpty()) {
while(cur != null) {
stack.push(cur);
cur = cur.left;
}
cur = stack.pop();
if(isFirst) {
pre = cur;
head = cur;
isFirst = false;
}else {
cur.left = pre;
pre.right = cur;
pre = cur;
}
cur = cur.right;
}
return head;
}
}
方法二:递归遍历
public class Solution {
public TreeNode Convert(TreeNode root) {
if(root == null) return null;
if(root.left == null && root.right == null) return root;
TreeNode left = Convert(root.left);
TreeNode p = left;
while(p != null && p.right != null) {
p = p.right;
}
if(p != null) {
p.right = root;
root.left = p;
}
TreeNode right = Convert(root.right);
if(right != null) {
right.left = root;
root.right = right;
}
return left != null ? left : root;
}
}
方法二的改进
解题思路:
思路与方法二中的递归版一致,仅对第2点中的定位作了修改,新增一个全局变量记录左子树的最后一个节点。
public class Solution {
TreeNode leftLast = null;
public TreeNode Convert(TreeNode root) {
if(root == null) return null;
if(root.left == null && root.right == null) {
leftLast = root;
return root;
}
TreeNode left = Convert(root.left);
if(left != null) {
leftLast.right = root;
root.left = leftLast;
}
leftLast = root;
TreeNode right = Convert(root.right);
if(right != null) {
right.left = root;
root.right = right;
}
return left != null ? left : root;
}
}