輸入一棵二叉搜索樹,將該二叉搜索樹轉換成一個排序的雙向鏈表。要求不能創建任何新的結點,只能調整樹中結點指針的指向。
這道題仔細看,就會發現是中序遍歷+改變指針指向。
但我就是那麼菜,明明知道了總體思路還是不會編,最後看了討論區中的高票回答,豁然開朗。
中序遍歷分爲遞歸和非遞歸。
非遞歸遍歷時,由於需要更改指針,所以需要增加一個節點記錄上一次遍歷到的節點。
遞歸遍歷時,就是先遞歸求出左子樹的結果,返回左子樹的雙向鏈表的第一個節點,然後我們對這個雙向鏈表遍歷,得到它的最後一個節點,然後加上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;
}
}