劍指offer-樹(JavaScript)
樹
7. 重建二叉樹
題目描述
輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。
例如,給出
前序遍歷 preorder = [3,9,20,15,7]
中序遍歷 inorder = [9,3,15,20,7]
返回如下的二叉樹:
3
/ \
9 20
/ \
15 7
程式碼
/** * Definition for a binary tree node. * function TreeNode(val) { * this.val = val; * this.left = this.right = null; * } */ /** * @param {number[]} preorder * @param {number[]} inorder * @return {TreeNode} */ var buildTree = function(preorder, inorder) { if(preorder.length==0 || inorder.length==0) return null; var root=preorder[0]; var index = inorder.indexOf(root); var left = inorder.slice(0, index); var right = inorder.slice(index+1); var node = new TreeNode(root); node.left = buildTree(preorder.slice(1,index+1), left); node.right = buildTree(preorder.slice(index+1), right); return node; };
8. 二叉樹的下一個節點
題目描述
給定一個二叉樹其中的一個結點,請找出中序遍歷順序的下一個結點並且返回。注意,樹中的結點不僅包含左右子結點,同時包含指向父結點的next指標。下圖為一棵有9個節點的二叉樹。樹中從父節點指向子節點的指標用實線表示,從子節點指向父節點的用虛線表示。
例如
輸入:{8,6,10,5,7,9,11},8 返回:9 解析:這個組裝傳入的子樹根節點,其實就是整顆樹,中序遍歷{5,6,7,8,9,10,11},根節點8的下一個節點就是9,應該返回{9,10,11},後臺只打印子樹的下一個節點,所以只會列印9,如下圖,其實都有指向左右孩子的指標,還有指向父節點的指標,下圖沒有畫出來
程式碼
/*function TreeLinkNode(x){ this.val = x; this.left = null; this.right = null; this.next = null; }*/ function GetNext(pNode) { // write code here if (pNode === null) return null; //空結點 var p = null; if (pNode.right) { //有右子樹,則下一個結點在右子樹最左邊的結點 p = pNode.right; while (p.left !== null) { p = p.left; } return p; } else { //沒有右子樹 p = pNode.next; if (p && p.right === pNode) { while (p.next && p.next.right === p) { p = p.next; } p = p.next; } return p; } return null; }
26. 樹的子結構
題目描述
輸入兩棵二叉樹A和B,判斷B是不是A的子結構。(約定空樹不是任意一個樹的子結構)
B是A的子結構, 即 A中有出現和B相同的結構和節點值。
例如:
給定的樹 A:
3
/ \
4 5
/ \
1 2
給定的樹 B:
4
/
1
返回 true,因為 B 與 A 的一個子樹擁有相同的結構和節點值。
示例 1:
輸入:A = [1,2,3], B = [3,1]
輸出:false
示例 2:
輸入:A = [3,4,5,1,2], B = [4,1]
輸出:true
程式碼
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} A
* @param {TreeNode} B
* @return {boolean}
*/
var isSubStructure = function(A, B) {
if(!A || !B) return false;
return isSame(A, B) || isSubStructure(A.left, B) || isSubStructure(A.right, B);
};
var isSame = function(A, B){
if(!B) return true;
if(!A) return false;
if(A.val != B.val) return false;
return isSame(A.left, B.left) && isSame(A.right, B.right);
}
27.二叉樹的映象
題目描述
請完成一個函式,輸入一個二叉樹,該函式輸出它的映象。
例如輸入:
4
/ \
2 7
/ \ / \
1 3 6 9
映象輸出:
4
/ \
7 2
/ \ / \
9 6 3 1
示例 1:
輸入:root = [4,2,7,1,3,6,9]
輸出:[4,7,2,9,6,3,1]
程式碼
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {TreeNode}
*/
var mirrorTree = function(root) {
if(!root) return root;
[root.left, root.right] = [root.right, root.left];
mirrorTree(root.left);
mirrorTree(root.right);
return root
};
28.對稱的二叉樹
題目描述
請實現一個函式,用來判斷一棵二叉樹是不是對稱的。如果一棵二叉樹和它的映象一樣,那麼它是對稱的。
例如,二叉樹 [1,2,2,3,4,4,3] 是對稱的。
1
/ \
2 2
/ \ / \
3 4 4 3
但是[1,2,2,null,3,null,3] 則不是映象對稱的:
1
/ \
2 2
\ \
3 3
示例 1:
輸入:root = [1,2,2,3,4,4,3]
輸出:true
示例 2:
輸入:root = [1,2,2,null,3,null,3]
輸出:false
程式碼
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {boolean}
*/
var isSymmetric = function(root) {
if(!root) return true;
return isSame(root.left, root.right)
};
var isSame = function(A, B){
if(!A && !B) return true;
if(!A) return false;
if(!B) return false;
if(A.val != B.val) return false;
return isSame(A.left, B.right) && isSame(A.right, B.left);
}
32-I.從上到下列印二叉樹
從上到下打印出二叉樹的每個節點,同一層的節點按照從左到右的順序列印。
例如:
給定二叉樹: [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回:
[3,9,20,15,7]
程式碼
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {number[]}
*/
var levelOrder = function(root) {
if(!root) return [];
let nodes = [];
nodes.push(root);
let res = [];
while(nodes.length > 0){
node = nodes.shift();
res.push(node.val);
node.left && nodes.push(node.left);
node.right && nodes.push(node.right);
}
return res;
};
32-II.從上到下列印二叉樹II
題目描述
從上到下按層列印二叉樹,同一層的節點按從左到右的順序列印,每一層列印到一行。
例如:
給定二叉樹: [3,9,20,null,null,15,7]
,
3
/ \
9 20
/ \
15 7
返回其層次遍歷結果:
[
[3],
[9,20],
[15,7]
]
程式碼
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {number[][]}
*/
var levelOrder = function(root) {
if(!root) return []
let nodes = [] // 存放當前節點
let layer = 0 // 表示當前層數
let res = []
nodes.push(root)
while(nodes.length){
res[layer] = []
let num = nodes.length
while(num--){
let node = nodes.shift()
res[layer].push(node.val)
node.left && nodes.push(node.left)
node.right && nodes.push(node.right)
}
layer++
}
return res
};
54. 二叉搜尋樹的第k大節點
題目描述
給定一棵二叉搜尋樹,請找出其中第k大的節點。
示例 1:
輸入: root = [3,1,4,null,2], k = 1
3
/ \
1 4
\
2
輸出: 4
示例 2:
輸入: root = [5,3,6,2,4,null,null,1], k = 3
5
/ \
3 6
/ \
2 4
/
1
輸出: 4
程式碼
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @param {number} k
* @return {number}
*/
var kthLargest = function(root, k) {
let res
let num = 0
const dfs = function(root){
if(root === null){
return
}
dfs(root.right)
num++
if(num === k){
res = root.val
}
dfs(root.left)
}
dfs(root)
return res
};
55-I. 二叉樹的深度
題目描述
輸入一棵二叉樹的根節點,求該樹的深度。從根節點到葉節點依次經過的節點(含根、葉節點)形成樹的一條路徑,最長路徑的長度為樹的深度。
例如:
給定二叉樹 [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回它的最大深度 3 。
程式碼
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {number}
*/
var maxDepth = function(root) {
if(root === null) return 0
return Math.max(maxDepth(root.left), maxDepth(root.right))+1
};
55-II. 平衡二叉樹
題目描述
輸入一棵二叉樹的根節點,判斷該樹是不是平衡二叉樹。如果某二叉樹中任意節點的左右子樹的深度相差不超過1,那麼它就是一棵平衡二叉樹。
示例 1:
給定二叉樹 [3,9,20,null,null,15,7]
3
/ \
9 20
/ \
15 7
返回 true 。
程式碼
function IsBalanced_Solution(pRoot) {
return depth(pRoot) !== -1;
}
// 用遞迴來判斷root是不是平衡二叉樹,如果不是則返回最大的深度,如果不是則返回-1
function depth(root) {
if (root === null) return 0;
var left = depth(root.left);
if (left === -1) return -1;
var right = depth(root.right);
if (right === -1) return -1;
if (Math.abs(left - right) > 1) {
return -1;
} else {
return 1 + Math.max(left, right);
}
}
68-I. 二叉搜尋樹的最近公共祖先
題目描述
給定一個二叉搜尋樹, 找到該樹中兩個指定節點的最近公共祖先。
百度百科中最近公共祖先的定義為:“對於有根樹 T 的兩個結點 p、q,最近公共祖先表示為一個結點 x,滿足 x 是 p、q 的祖先且 x 的深度儘可能大(一個節點也可以是它自己的祖先)。”
例如,給定如下二叉搜尋樹: root = [6,2,8,0,4,7,9,null,null,3,5]
示例 :
輸入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
輸出: 6
解釋: 節點 2 和節點 8 的最近公共祖先是 6。
輸入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4
輸出: 2
解釋: 節點 2 和節點 4 的最近公共祖先是 2, 因為根據定義最近公共祖先節點可以為節點本身。
程式碼
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @param {TreeNode} p
* @param {TreeNode} q
* @return {TreeNode}
*/
var lowestCommonAncestor = function(root, p, q) {
while(root){
if(root.val<p.val && root.val<q.val){
root = root.right
} else if(root.val>p.val && root.val>q.val) {
root = root.left
} else {
break
}
}
return root
};
68-II. 二叉樹的最近公共祖先
題目描述
例如,給定如下二叉樹: root = [3,5,1,6,2,0,8,null,null,7,4]
示例 1:
輸出: 3
解釋: 節點 5 和節點 1 的最近公共祖先是節點 3。```
示例 2:
輸出: 5
解釋: 節點 5 和節點 4 的最近公共祖先是節點 5。因為根據定義最近公共祖先節點可以為節點本身。```
程式碼
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @param {TreeNode} p
* @param {TreeNode} q
* @return {TreeNode}
*/
var lowestCommonAncestor = function(root, p, q) {
if (!root || root === p || root === q) return root;
const left = lowestCommonAncestor(root.left, p, q);
const right = lowestCommonAncestor(root.right, p, q);
// 左子樹找不到,返回右子樹
if (!left) return right;
// 右子樹找不到,返回左子樹
if (!right) return left;
// 左右子樹都找到了,那麼root就是要找的
return root;
};