面試題36 二叉搜索樹與雙向鏈表
題目描述
輸入一棵二叉搜索樹,將該二叉搜索樹轉換成一個排序的雙向鏈表。要求不能創建任何新的結點,只能調整樹中結點指針的指向。
題解
題目要求排序的雙向鏈表,則:
- 採用中序遍歷,剛好節點的值爲一個遞增的序列。
- 雙向鏈表: 則鏈表中相鄰的兩個節點之間(如果驅節點 pre ,當前節點 cur)有則 pre.right = cur, cur.left = pre
算法流程
採用非遞歸的中序dfs,用一個棧記錄訪問次序,一個輔助鏈表記錄訪問結果,在輔助鏈表中修改指針指向。返回輔助鏈表的第一個節點;
複雜度分析:
時間複雜度 O(N) : N 爲二叉樹的節點數,中序遍歷需要訪問所有節點。
空間複雜度 O(N) : 輔助鏈表res使用 O(N)空間。輔助棧stack最差情況下也是O(N)空間。
import java.util.ArrayList;
import java.util.Stack;
public class Solution {
public TreeNode Convert(TreeNode pRootOfTree) {
if(pRootOfTree == null) return null;
if(pRootOfTree.left == null && pRootOfTree.right == null) return pRootOfTree;
ArrayList<TreeNode> res = new ArrayList<>();
Stack<TreeNode> stack = new Stack<TreeNode>();
TreeNode temp = pRootOfTree;
// 形成一箇中序遍歷的結果,並添加指針。
while(!stack.empty() || temp != null){
if(temp != null){
stack.add(temp);
temp = temp.left;
}else{
temp = stack.pop();
res.add(temp);
temp = temp.right;
}
}
// 修改鏈表指針指向。
for(int i = 0; i < res.size()-1; i++){
res.get(i+1).left = res.get(i);
res.get(i).right = res.get(i+1);
}
return res.get(0);
}
}
遞歸寫法:
時間複雜度 O(N) : N 爲二叉樹的節點數,中序遍歷需要訪問所有節點。
空間複雜度 O(N) : 當二叉樹退化爲鏈表時,遞歸輔助棧最差情況下也是O(N)空間。
public class Solution {
TreeNode head = null;
TreeNode pre = null;
public TreeNode Convert(TreeNode pRootOfTree) {
dfs(pRootOfTree);
return head;
}
void dfs(TreeNode cur){
if(cur == null) return ;
dfs(cur.left);
if(pre != null) pre.right = cur; // 一般情況
else head = cur;
cur.left = pre;
pre = cur;
dfs(cur.right);
}
}