船长表情包镇楼
二叉树
- 每个节点度最多为2
- 度为0的节点比度为2的节点多1个
遍历
- 前序遍历:根左右
- 中序遍历:左根右
- 后序遍历:左右根
相关二叉树
- 完全二叉树:仅最后一层右侧取缺少子节点的二叉树
- 满二叉树:没有度为1节点的二叉树
- 完美二叉树:最后一层都没有孩子的满二叉树
完全二叉树
- 编号为i的子节点
左孩子编号:2i
右孩子编号:2i+1
- 可以用连续空间存储(数组)
一维与二维的相通
树结构的深入理解
- 节点代表集合,边代表关系,子节点代表性质互不相同的子集
设计理解递归程序
- 数学归纳法-> 结构归纳法
- 赋予递归函数一个明确的意义
- 思考边界条件
- 实现递归过程
船长金句:谁会在乎递归函数是怎么执行的呢,我们只要关注这个函数的意义即可!
LeetCode肝题
- LeetCode 144. 二叉树的前序遍历
var preorder = function(root, ans) {
if(root === null) return null
ans.push(root.val)
preorder(root.left, ans)
preorder(root.right, ans)
}
var preorderTraversal = function(root) {
let ans = []
preorder(root, ans)
return ans
};
-
- N 叉树的前序遍历
var __preorder = function(root, ans) {
if(!root.children) return
ans.push(root.val)
for(let i = 0; i<root.children.length; i++) {
__preorder(root.children[i], ans)
}
};
var preorder = function(root) {
if (!root) return []
let ans = []
__preorder(root, ans)
return ans
};
-
- 翻转二叉树
var reverse = function(root) {
if (!root) return
let a = root.right
root.right = root.left
root.left = a
reverse(root.left)
reverse(root.right)
}
var invertTree = function(root) {
reverse(root)
return root
};
- 剑指 Offer 32 - II. 从上到下打印二叉树 II
var getResult = function(root, k, ans) {
if (!root) return
if (k == ans.length) ans.push([])
ans[k].push(root.val)
getResult(root.left, k + 1, ans)
getResult(root.right, k + 1, ans)
}
var levelOrder = function(root) {
let ans = []
getResult(root, 0, ans)
return ans
};
-
- 二叉树的层序遍历 II
var getResult = function(root, k, ans) {
if (!root) return
if (k == ans.length) ans.push([])
ans[k].push(root.val)
getResult(root.left, k+1, ans)
getResult(root.right, k+1, ans)
}
var resver = function(arr) {
for(let i=0, j=arr.length-1; i<j;i++,j--) {
[arr[i],arr[j]] = [arr[j], arr[i]]
}
}
var levelOrderBottom = function(root) {
if (!root) return []
let ans = []
getResult(root, 0, ans)
resver(ans)
return ans
};
-
- 二叉树的锯齿形层序遍历
var getResult = function(root, k, ans) {
if (!root) return
if (k ==ans.length) ans.push([])
ans[k].push(root.val)
getResult(root.left, k+1, ans)
getResult(root.right, k+1, ans)
}
var resves = function(arr) {
for(let i=0,j=arr.length-1;i<j;i++,j--) {
[arr[i], arr[j]] = [arr[j], arr[i]]
}
}
var zigzagLevelOrder = function(root) {
if (!root) return []
let ans = []
getResult(root, 0, ans)
for(let i = 0; i<ans.length; i++) {
if (i%2==1) {
resves(ans[i])
}
}
return ans
};
-
- 平衡二叉树
var getHeight = function(root) {
if (!root) return 0
let l = getHeight(root.left)
let r = getHeight(root.right)
if (l<0 || r<0) return -2
if (Math.abs(l - r) > 1) return -2
return Math.max(l, r) + 1
}
var isBalanced = function(root) {
if (!root) return true
return getHeight(root) > 0
};
-
- 路径总和
var hasPathSum = function(root, targetSum) {
if(!root) return false
if (!root.left && !root.right) return root.val == targetSum
if (root.left && hasPathSum(root.left, targetSum - root.val)) return true
if (root.right && hasPathSum(root.right, targetSum - root.val)) return true
return false
};
-
- 从前序与中序遍历序列构造二叉树
核心图解
var buildTree = function(preorder, inorder) {
if(preorder.length==0) return null
let pos = inorder.findIndex(item => item == preorder[0])
let l_pre = [],l_in = [],r_pre = [],r_in = []
for(let i = 0; i < pos; i++) {
l_pre.push(preorder[i+1])
l_in.push(inorder[i])
}
for(let i = pos+1; i < preorder.length; i++) {
r_pre.push(preorder[i])
r_in.push(inorder[i])
}
let root = new TreeNode(preorder[0])
root.left = buildTree(l_pre, l_in)
root.right = buildTree(r_pre, r_in)
return root
};
-
- 完全二叉树的结点个数
var countNodes = function(root) {
if(!root) return 0
return countNodes(root.left) + countNodes(root.right) + 1
};
- 剑指 Offer 54. 二叉搜索树的第 k 大结点
二叉搜索树:右子树的值总是大于根节点,左子树的值总是小于根节
所以二叉搜索树的中序遍历结果是一个有序数组
var inorder = function(root, ans) {
if (!root) return
root.left && inorder(root.left,ans)
ans.push(root.val)
root.right && inorder(root.right,ans)
}
var kthLargest = function(root, k) {
let ans = []
inorder(root, ans)
return ans[ans.length -k]
};
- 剑指 Offer 26. 树的子结构
var is_match = function(A, B) {
if (B == null) return true
if (A == null) return false
if (A.val != B.val) return false
return is_match(A.left, B.left) && is_match(A.right, B.right)
}
var isSubStructure = function(A, B) {
if (A == null) return false
if (B == null) return false
if (A.val == B.val && is_match(A, B)) return true
return isSubStructure(A.left, B) || isSubStructure(A.right, B)
};
-
- 二叉树最大宽度
var widthOfBinaryTree = function(root) {
if (!root) return 0
let max = 1, que = [[0, root]]
while(que.length) {
let smaller = que[0][0], bigger = que[que.length - 1][0]
max = Math.max(max, bigger - smaller + 1)
let arr = []
for (const [index, item] of que) {
item.left && arr.push([2*(index - smaller), item.left])
item.right && arr.push([2*(index - smaller)+1, item.right])
}
que = arr
}
return max
};