輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。node
例如,給出數組
前序遍歷 preorder = [3,9,20,15,7] 中序遍歷 inorder = [9,3,15,20,7] 返回以下的二叉樹:markdown
3
/ \
9 20
/ \
15 7
複製代碼
限制:函數
0 <= 節點個數 <= 5000post
對於一個二叉樹來講,前序遍歷的第一個元素就是二叉樹的父節點,咱們能夠根據父節點找到父節點在中序遍歷中的位置index,根據index咱們就能夠將 中序遍歷分爲左右兩個子樹,這兩個子樹也是中序遍歷。根據index咱們也能夠找到左子樹和右子樹的前序遍歷。這是咱們就能夠獲得四個數組,分別是中序遍歷的左子樹和右子樹,前序遍歷的左子樹和右子樹,因此咱們就能夠遞歸地調用函數,分別去找左子樹和右子樹的父節點,找到後賦值給node.left和node.right。結束遞歸的條件就是前序遍歷的數組只有一個元素,說明只有根元素,左右子樹爲空,就返回這個節點。ui
/* 前序遍歷:跟節點 + 左子樹前序遍歷 + 右子樹前序遍歷 中序遍歷:左子樹中序遍歷 + 跟節點 + 右字數中序遍歷 後序遍歷:左子樹後序遍歷 + 右子樹後序遍歷 + 跟節點 根據上面的規律: 前序遍歷找到根結點root 找到root在中序遍歷的位置 -> 左子樹的長度和右子樹的長度 截取左子樹的中序遍歷、右子樹的中序遍歷 截取左子樹的前序遍歷、右子樹的前序遍歷 遞歸重建二叉樹 */
class Node {
constructor(data, left, right) {
this.data = data;
this.left = left;
this.right = right
}
show() {
console.log(this.data);
}
};
function rebuildTree(pre,mid) {
if (pre.length === 0) {
return null;
}
if (pre.length === 1) {
return new Node(pre[0])
}
const data = pre[0];
const index = mid.indexOf(data);
const midLeft = mid.slice(0,index);
const midRight = mid.slice(index+1);
const preLeft = pre.slice(1,index+1);
const preRight = pre.slice(index+1);
const node = new Node(data);
node.left = rebuildTree(preLeft,midLeft);
node.right = rebuildTree(preRight,midRight);
return node;
}
let preorder = [3,9,20,15,7];
let inorder = [9,3,15,20,7];
console.log( rebuildTree(preorder,inorder));
複製代碼
對於任意一顆樹而言,前序遍歷的形式老是this
[ 根節點, [左子樹的前序遍歷結果], [右子樹的前序遍歷結果] ]
複製代碼
即根節點老是前序遍歷中的第一個節點。而中序遍歷的形式老是spa
[ [左子樹的中序遍歷結果], 根節點, [右子樹的中序遍歷結果] ]
複製代碼
只要咱們在中序遍歷中定位到根節點,那麼咱們就能夠分別知道左子樹和右子樹中的節點數目。因爲同一顆子樹的前序遍歷和中序遍歷的長度顯然是相同的,所以咱們就能夠對應到前序遍歷的結果中,對上述形式中的全部左右括號進行定位。code
這樣以來,咱們就知道了左子樹的前序遍歷和中序遍歷結果,以及右子樹的前序遍歷和中序遍歷結果,咱們就能夠遞歸地對構造出左子樹和右子樹,再將這兩顆子樹接到根節點的左右位置。orm
本文正在參與「掘金 2021 春招闖關活動」, 點擊查看 活動詳情