[TOC]
# 1.重建二叉树
[牛客网链接](https://www.nowcoder.com/practice/8a19cbe657394eeaac2f6ea9b0f6fcf6?tpId=13&tqId=11157&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking)
题目描述:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列 {1,2,4,7,3,5,6,8} 和中序遍历序列 {4,7,2,1,5,3,8,6},则重建二叉树并返回。
解题思路:
前序序列第一个数将中序序列划分为根和左右子树,递归地利用这个规律来构建二叉树
```
function TreeNode(x) {
this.val = x;
this.left = null;
this.right = null;
}
function reConstructBinaryTree(pre, vin)
{
// write code here
if (pre.length === 0 || vin.length === 0) return null // slice划分时越界会返回[]
let root = new TreeNode(pre[0])
let index = vin.indexOf(pre[0])
root.left = reConstructBinaryTree(pre.slice(1, index+1), vin.slice(0, index))
root.right = reConstructBinaryTree(pre.slice(index + 1), vin.slice(index+1))
return root
}
```
# 2.树的子结构
[牛客网链接](https://www.nowcoder.com/practice/6e196c44c7004d15b1610b9afca8bd88?tpId=13&tqId=11170&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking)
题目描述:输入两棵二叉树 A,B,判断 B 是不是 A 的子结构。(ps:我们约定空树不是任意一个树的子结构)
解题思路:递归:首先判断根结点的值是否相等,如果相等则进一步判断左右结点是否相等,否则判断 A 的左子树是否包含B(true 的话则会返回,false 则会继续判断右边),A 的右子树是否包含 B,另外注意 null 是非 null 树的子结构
```
function isSubTree(pA, pB) {
if (pB === null) return true // 空的话肯定是A的子树,注意优先判断pB
if (pA === null) return false // 判断B是否为A的子树,A为空的话肯定不是了
if (pA.val === pB.val) {
return isSubTree(pA.left, pB.left) && isSubTree(pA.right, pB.right) // 短路特性,同时为true才为true
} else {
return false
}
}
function HasSubtree(pRoot1, pRoot2)
{
// write code here
if (pRoot1 === null || pRoot2 === null) return false
return isSubTree(pRoot1, pRoot2) || HasSubtree(pRoot1.left, pRoot2)
|| HasSubtree(pRoot1.right, pRoot2)
}
```
# 3.二叉树的镜像
[牛客网链接](https://www.nowcoder.com/practice/564f4c26aa584921bc75623e48ca3011?tpId=13&tqId=11171&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking)
题目描述:操作给定的二叉树,将其变换为源二叉树的镜像。
![](https://box.kancloud.cn/64529323980c09343ae42be2169154b8_259x369.png)
解题思路:递归:先交换最下层的结点的左右子树,再交换上层的左右子树
```
function Mirror(root)
{
// write code here
if (root === null) return null
if (root.left !== null) {
Mirror(root.left)
}
if (root.right !== null) {
Mirror(root.right)
}
if (root.left === null && root.right === null) return
let tmp = root.left
root.left = root.right
root.right = tmp
return root
}
```
# 4.从上往下打印二叉树
[牛客网链接](https://www.nowcoder.com/practice/7fe2212963db4790b57431d9ed259701?tpId=13&tqId=11175&tPage=2&rp=2&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking)
题目描述:从上往下打印出二叉树的每个节点,同层节点从左至右打印。
解题思路:使用队列,先放入根结点,再放入左右子结点,广搜
```
function PrintFromTopToBottom(root)
{
// write code here
let queue = []
const res = []
if (root === null) return res
queue.push(root) // 队列->层次遍历
while(queue.length !== 0) {
let top = queue.shift()
res.push(top.val)
if (top.left !== null) {
queue.push(top.left)
}
if (top.right !== null) {
queue.push(top.right)
}
}
return res
}
```
# 5.二叉搜索树(BST)的后序遍历序列
[牛客网链接](https://www.nowcoder.com/practice/a861533d45854474ac791d90e447bafd?tpId=13&tqId=11176&tPage=2&rp=2&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking)
题目描述:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
```
function VerifySquenceOfBST(sequence)
{
// write code here
// BST特性:左子结点比根结点小,右子结点大于根结点
let size = sequence.length
if (size === 0) return false
let i = 0
while (--size) { // "根"总为数组最后一个元素
while (sequence[i++] < sequence[size]); // 左子树都应该小于根元素
while (sequence[i++] > sequence[size]); // 右子树都应该大于根元素
if (i < size) return false // 理论上上面两个循环都应该到达最后一个元素
i = 0
}
return true
}
```
解题思路:非递归方法 -> 看注释
# 6.二叉树中和为某一个值的路径
[牛客网链接](https://www.nowcoder.com/practice/b736e784e3e34731af99065031301bca?tpId=13&tqId=11177&tPage=2&rp=2&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking)
题目描述:输入一颗二叉树的跟节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)
解题思路:dfs的思想,关键是路径的保存;注意题目中“路径”指的是到达叶结点的,中间结点不用判断,整体思路:如果为叶结点则判断累计的和是否与指定的数相等,如果相等,则添加当前路径;dfs的时候注意返回的时候路径弹出当前结点。
```
var path;
var stack;
function FindPath(root, expectNumber)
{
// write code here
if(root == null){
return [];
}
path= [];
stack = [];
cal(root,expectNumber);
return path;
}
function cal(root,expectNumber){
stack.push(root.val);
if(root.val == expectNumber && root.left==null && root.right==null){
path.push(stack.slice());
}
else{
if(root.left!=null){
cal(root.left,expectNumber-root.val);
}
if(root.right!=null){
cal(root.right,expectNumber-root.val);
}
}
stack.pop();
}
```
# 7.二叉树的深度
题目描述:输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
```js
var maxDepth = function (root) {
if (root === undefined || root === null) {
return 0
}
return Math.max(maxDepth(root.left),maxDepth(root.right)) + 1
}
```
# 8.平衡二叉树
[牛客网链接](https://www.nowcoder.com/practice/8b3b95850edb4115918ecebdf1b4d222?tpId=13&tqId=11192&tPage=2&rp=2&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking)
题目描述:输入一棵二叉树,判断该二叉树是否是平衡二叉树。
平衡二叉搜索树(Self-balancing binary search tree)又被称为AVL树(有别于AVL算法),且具有以下性质:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。平衡二叉树的常用实现方法有红黑树、AVL、替罪羊树、Treap、伸展树等。 最小二叉平衡树的节点总数的公式如下 F(n)=F(n-1)+F(n-2)+1 这个类似于一个递归的数列,可以参考Fibonacci(斐波那契)数列,1是根节点,F(n-1)是左子树的节点数量,F(n-2)是右子树的节点数量。
```
// 平衡二叉树:左右子树高度差不超过1,且左右子树也是平衡二叉树
function IsBalanced_Solution(pRoot)
{
// write code here
if (pRoot === null) return true
let leftTreeDeep = getDeep(pRoot.left)
let rightTreeDeep = getDeep(pRoot.right)
if (Math.abs(leftTreeDeep - rightTreeDeep) > 1) {
return false
}
return IsBalanced_Solution(pRoot.left) && IsBalanced_Solution(pRoot.right)
}
// 获取树的高度
function getDeep(root) {
if (root === null) return 0
let left = getDeep(root.left)
let right = getDeep(root.right)
return left > right ? left + 1 : right + 1
}
```
# 9.对称的二叉树
[牛客网链接](https://www.nowcoder.com/practice/ff05d44dfdb04e1d83bdbdab320efbcb?tpId=13&tqId=11211&tPage=3&rp=3&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking)
题目描述:请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
解题思路:如果二叉树是对称的,左子树的左子树和右子树的右子树相同,左子树的右子树和右子树的左子树相同即可
```
function isSymmetrical(pRoot)
{
if(pRoot==null){
return true;
}
return jury(pRoot,pRoot);
}
function jury(root1,root2){
if(root1==null && root2==null){
return true;
}
if((root1==null && root2!=null)||(root1!=null && root2==null)){
return false;
}
if(root1.val!==root2.val){
return false;
}
return(jury(root1.left,root2.right)&&jury(root2.left,root1.right));
}
```
# 10.按之字形顺序打印二叉树
[牛客网链接](https://www.nowcoder.com/practice/91b69814117f4e8097390d107d2efbe0?tpId=13&tqId=11212&tPage=3&rp=3&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking)
题目描述:请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
```
function Print(pRoot)
{
// write code here
// 奇数行从左往右,偶数行从右往左
const res = [], queue = []
let level = 1
if (pRoot === null) return res
queue.push(pRoot)
while (queue.length !== 0) { // 每轮弹出一层的结点并放入下一层的
let low = 0, high = queue.length // 确定每层的结点数
const line = []
while (low++ < high) {
let tmp = queue.shift()
line.push(tmp.val)
if (tmp.left !== null) { queue.push(tmp.left) }
if (tmp.right !== null) { queue.push(tmp.right) }
}
if (level % 2 === 0) {
res.push(line.reverse())
} else {
res.push(line)
}
level++
}
return res
}
```
# 递归篇
一棵树要么是空树,要么有两个指针,每个指针指向一棵树。树是一种递归结构,很多树的问题可以使用递归来处理。
## 1、树的高度
[104\. Maximum Depth of Binary Tree (Easy)](https://leetcode.com/problems/maximum-depth-of-binary-tree/description/)
```js
/**
* @param {TreeNode} root
* @return {number}
*/
var maxDepth = function(root) {
if (root === null) return 0
return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1
};
```
## 2、平衡树
[110\. Balanced Binary Tree (Easy)](https://leetcode.com/problems/balanced-binary-tree/description/)
```html
3
/ \
9 20
/ \
15 7
```
平衡树左右子树高度差都小于等于 1
```js
var isBalanced = function(root) {
if (root === null) return true
let left = depth(root.left)
let right = depth(root.right)
return Math.abs(left - right) <= 1 && isBalanced(root.left) && isBalanced(root.right)
};
function depth (root) {
if (root === null) return 0
let l = depth(root.left)
let r = depth(root.right)
return Math.max(l, r) + 1
}
```
## 3.两节点的最长路径
[543\. Diameter of Binary Tree (Easy)](https://leetcode.com/problems/diameter-of-binary-tree/description/)
```
Input:
1
/ \
2 3
/ \
4 5
Return 3, which is the length of the path [4,2,1,3] or [5,2,1,3].
```
```js
var diameterOfBinaryTree = function(root) {
let max = 0
maxDepth(root)
function maxDepth (root) {
if (root === null) return 0
let left = maxDepth(root.left)
let right = maxDepth(root.right)
max = Math.max(max, left + right) // 这一步很关键
return Math.max(left, right) + 1
}
return max
};
```
## 翻转树
[226\. Invert Binary Tree (Easy)](https://leetcode.com/problems/invert-binary-tree/description/)
```js
var invertTree = function(root) {
if (root === null) return null
let left = root.left
root.left = invertTree(root.right)
root.right = invertTree(left)
return root
};
```
## 归并两棵树
[617\. Merge Two Binary Trees (Easy)](https://leetcode.com/problems/merge-two-binary-trees/description/)
```js
Input:
Tree 1 Tree 2
1 2
/ \ / \
3 2 1 3
/ \ \
5 4 7
Output:
3
/ \
4 5
/ \ \
5 4 7
```
```js
var mergeTrees = function(t1, t2) {
if (t1 === null && t2 === null) return null
if (t1 === null) return t2
if (t2 === null) return t1
let root = new TreeNode(t1.val + t2.val)
root.left = mergeTrees(t1.left, t2.left)
root.right = mergeTrees(t1.right, t2.right)
return root
};
```
## 判断路径和是否等于一个数
[Leetcdoe : 112. Path Sum (Easy)](https://leetcode.com/problems/path-sum/description/)
```js
Given the below binary tree and sum = 22,
5
/ \
4 8
/ / \
11 13 4
/ \ \
7 2 1
return true, as there exist a root-to-leaf path 5->4->11->2 which sum is 22.
```
```js
var hasPathSum = function(root, sum) {
if (root === null) return false
if (root.left === null && root.right === null && root.val === sum) return true // 叶子结点
return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val)
};
```
## 统计路径和等于一个数的路径数量
[437\. Path Sum III (Easy)](https://leetcode.com/problems/path-sum-iii/description/)
```js
root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8
10
/ \
5 -3
/ \ \
3 2 11
/ \ \
3 -2 1
Return 3. The paths that sum to 8 are:
1. 5 -> 3
2. 5 -> 2 -> 1
3. -3 -> 11
```
路径不一定以 root 开头,也不一定以 leaf 结尾,但是必须连续。
```js
// pathSum:给他一个节点和一个目标值,他返回以这个节点为根的树中,和为目标值的路径总数。
## 子树
[572\. Subtree of Another Tree (Easy)](https://leetcode.com/problems/subtree-of-another-tree/description/)
```js
// 判断 t 是否为 s 的子树
var isSubtree = function(s, t) {
if (s === null) return false
return isSubtreeWithRoot(s, t) || isSubtree(s.left, t) || isSubtree(s.right, t)
};
// 判断以节点 t 为根结点其是否与 s 具有相同的结果
function isSubtreeWithRoot(s, t) {
if (t === null && s === null) return true
if (t === null || s === null) return false
if (t.val !== s.val) return false
return isSubtreeWithRoot(s.left, t.left) && isSubtreeWithRoot(s.right, t.right)
}
```
- 序言 & 更新日志
- H5
- Canvas
- 序言
- Part1-直线、矩形、多边形
- Part2-曲线图形
- Part3-线条操作
- Part4-文本操作
- Part5-图像操作
- Part6-变形操作
- Part7-像素操作
- Part8-渐变与阴影
- Part9-路径与状态
- Part10-物理动画
- Part11-边界检测
- Part12-碰撞检测
- Part13-用户交互
- Part14-高级动画
- CSS
- SCSS
- codePen
- 速查表
- 面试题
- 《CSS Secrets》
- SVG
- 移动端适配
- 滤镜(filter)的使用
- JS
- 基础概念
- 作用域、作用域链、闭包
- this
- 原型与继承
- 数组、字符串、Map、Set方法整理
- 垃圾回收机制
- DOM
- BOM
- 事件循环
- 严格模式
- 正则表达式
- ES6部分
- 设计模式
- AJAX
- 模块化
- 读冴羽博客笔记
- 第一部分总结-深入JS系列
- 第二部分总结-专题系列
- 第三部分总结-ES6系列
- 网络请求中的数据类型
- 事件
- 表单
- 函数式编程
- Tips
- JS-Coding
- Framework
- Vue
- 书写规范
- 基础
- vue-router & vuex
- 深入浅出 Vue
- 响应式原理及其他
- new Vue 发生了什么
- 组件化
- 编译流程
- Vue Router
- Vuex
- 前端路由的简单实现
- React
- 基础
- 书写规范
- Redux & react-router
- immutable.js
- CSS 管理
- React 16新特性-Fiber 与 Hook
- 《深入浅出React和Redux》笔记
- 前半部分
- 后半部分
- react-transition-group
- Vue 与 React 的对比
- 工程化与架构
- Hybird
- React Native
- 新手上路
- 内置组件
- 常用插件
- 问题记录
- Echarts
- 基础
- Electron
- 序言
- 配置 Electron 开发环境 & 基础概念
- React + TypeScript 仿 Antd
- TypeScript 基础
- 样式设计
- 组件测试
- 图标解决方案
- Algorithm
- 排序算法及常见问题
- 剑指 offer
- 动态规划
- DataStruct
- 概述
- 树
- 链表
- Network
- Performance
- Webpack
- PWA
- Browser
- Safety
- 微信小程序
- mpvue 课程实战记录
- 服务器
- 操作系统基础知识
- Linux
- Nginx
- redis
- node.js
- 基础及原生模块
- express框架
- node.js操作数据库
- 《深入浅出 node.js》笔记
- 前半部分
- 后半部分
- 数据库
- SQL
- 面试题收集
- 智力题
- 面试题精选1
- 面试题精选2
- 问答篇
- Other
- markdown 书写
- Git
- LaTex 常用命令