文章目录
p101 对称二叉树
/**
* 101. 对称二叉树
* 给你一个二叉树的根节点 root , 检查它是否轴对称。
* https://leetcode-cn.com/problems/symmetric-tree/
*/
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {boolean}
* 递归
*/
var isSymmetric = function (root) {
if (root === null) {
return true;
}
return dfs(root.left, root.right);
};
function dfs(left, right) {
if (left === null && right === null) {
return true;
}
if (left === null || right === null) {
return false;
}
//注意:此处需要用 !==
if (left.val !== right.val) {
return false;
}
return dfs(left.left, right.right) && dfs(left.right, right.left);
}
/**
* @param {TreeNode} root
* @return {boolean}
* 队列
*/
var isSymmetric2 = function (root) {
if (root === null) {
return true;
}
let queue = [];
queue.push(root);
while (queue.length > 0) {
let n = queue.length;
for (let i = 0; i < n; i ++) {
let node = queue.shift();
if (node.left === null && node.right)
if (node.left && node.right) {
}
}
}
return dfs(root.left, root.right);
};
p102 二叉树层次遍历
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {number[][]}
*/
var levelOrder = function (root) {
let res = [], queue = [];
queue.push(root);
if (root === null) {
return res;
}
//遍历队列,每次遍历都是一层,该层遍历完之后加入res
while (queue.length !== 0) {
var length = queue.length;
//存放每一层的节点
let level = [];
for (let i = 0; i < length; i++) {
//遍历当前节点,将val保存到level
let node = queue.shift();
level.push(node.val);
//存放当前层下一层的节点
node.left && queue.push(node.left);
node.right && queue.push(node.right);
}
//当层遍历完成,结果放入数组
res.push(level);
}
return res;
};
function TreeNode(val, left, right) {
this.val = (val === undefined ? 0 : val)
this.left = (left === undefined ? null : left)
this.right = (right === undefined ? null : right)
}
p103 之字形层次遍历
设一个flag,偶数反转
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {number[][]}
*/
var zigzagLevelOrder = function(root) {
let res = [], queue = [];
queue.push(root);
if (root === null) {
return res;
}
let flag = 0;
while (queue.length > 0) {
let n = queue.length;
let level = [];
flag++;
for (let i = 0; i < n; i++) {
let node = queue.shift();
level.push(node.val);
node.left && queue.push(node.left);
node.right && queue.push(node.right);
}
//flag记录遍历层次,偶数层level值反转
if (flag % 2 === 0) {
level.reverse();
}
res.push(level);
}
return res;
};
p104 二叉树的最大深度
/**
* 104. 二叉树的最大深度
* 给定一个二叉树,找出其最大深度。
* 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
* https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/
*/
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {number}
*/
var maxDepth = function(root) {
let queue = [], count = 0;
if (root === null) {
return 0;
}
queue.push(root);
while (queue.length > 0) {
let n = queue.length;
count ++;
for (let i = 0; i < n; i ++) {
let node = queue.shift();
node.left && queue.push(node.left);
node.right && queue.push(node.right);
}
}
return count;
};
p105 从前序与中序遍历构造二叉树
/**
* 105. 从前序与中序遍历序列构造二叉树
* 给定两个整数数组preorder 和 inorder,其中preorder 是二叉树的先序遍历,
* inorder是同一棵树的中序遍历,请构造二叉树并返回其根节点
* https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/
*/
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {number[]} preorder
* @param {number[]} inorder
* @return {TreeNode}
*/
var buildTree = function(preorder, inorder) {
//pos:用于将树的中序遍历 位置与值 相映射,即哈希表,查找为O(1)
let pos = {}
for (let i = 0; i < inorder.length; i ++) {
pos[inorder[i]] = i
}
return build(0, preorder.length - 1, 0, inorder.length - 1)
// pl pr:前序的左右端点位置 il ir:中序的左右端点位置
function build(pl, pr, il, ir) {
//初始条件判断
if (pl > pr) {
return null
}
//以前序的最左端点为根节点,建立树
let root = new TreeNode(preorder[pl])
// k:根节点的位置
let k = pos[root.val]
//建立左子树(画图求端点表达式)
root.left = build(pl + 1, pl + k - il, il, k - 1)
//建立右子树
root.right = build(pl + k - il + 1, pr, k + 1, ir)
return root;
}
};
树的哈希表映射:
let pos = {}
for (let i = 0; i < inorder.length; i ++) {
pos[inorder[i]] = i
}
p108 将有序数组转换为二叉搜索树
/**
* 题目描述:
* 108. 将有序数组转换为二叉搜索树
* 给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。
* 高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。
* https://leetcode-cn.com/problems/convert-sorted-array-to-binary-search-tree/
*/
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {number[]} nums
* @return {TreeNode}
*/
var sortedArrayToBST = function (nums) {
return build(0, nums.length - 1)
function build(l, r) {
//初始条件判断
if (l > r) {
return null
}
//以中间节点为根节点,建立二叉搜索树
let mid = l + r >> 1
let root = new TreeNode(nums[mid])
//建立左子树
root.left = build(l, mid - 1)
//建立右子树
root.right = build(mid + 1, r)
return root
}
};
p116 填充每个节点的下一个右侧节点指针
/**
* 题目描述:
* 116. 填充每个节点的下一个右侧节点指针
* 给定一个完美二叉树,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:
* struct Node {
* int val;
* Node *left;
* Node *right;
* Node *next;
* }
* 填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。
* 初始状态下,所有next 指针都被设置为 NULL。
* https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node/
*/
/**
* // Definition for a Node.
* function Node(val, left, right, next) {
* this.val = val === undefined ? null : val;
* this.left = left === undefined ? null : left;
* this.right = right === undefined ? null : right;
* this.next = next === undefined ? null : next;
* };
*/
/**
* @param {Node} root
* @return {Node}
* 思路:
* 层次遍历,queue,每层将节点串联起来
*/
var connect = function(root) {
let queue = []
queue.push(root)
if (root === null) {
return root
}
while (queue.length > 0) {
let n = queue.length
//每层遍历时将该层的节点串联起来
let node = queue[0]
for (let i = 1; i < n; i ++) {
node.next = queue[i]
node = queue[i]
}
//遍历该层,将该层的左右节点放入queue
for (let i = 0; i < n; i ++) {
node = queue.shift()
node.left && queue.push(node.left)
node.right && queue.push(node.right)
}
}
return root
};
p572 另一棵树的子树
/**
* 572. 另一棵树的子树
* 给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。
* 二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。
* https://leetcode-cn.com/problems/subtree-of-another-tree/
*/
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} s
* @param {TreeNode} t
* @return {boolean}
* 思路:树哈希
* 如果两棵树形态相同,哈希值相同;形态不同,哈希值大概率不同
* (树哈希和字符串哈希一般不考虑冲突,因为冲突的概率非常小)
*/
var isSubtree = function(s, t) {
//P Q:取一个较大的质数 MOD:用于取模,保证范围
let P = 131, Q = 159, MOD = 1e4 + 7
//S T:s t的哈希值(均设置为正数),子树t初始化为-1
let S, T = -1
//res:返回结果,默认false
let res = false
//求子树t的哈希值
T = dfs(t)
//如果t的哈希值和s的哈希值相同,说明t是s的子树
if (T === dfs(s)) {
res = true
}
return res
//求以root为根节点的树的哈希值
function dfs(root) {
//如果根节点为空,随便返回一个不为0的值
if (root === null) {
return 12345
}
//求左子树、右子树的哈希值
let left = dfs(root.left), right = dfs(root.right)
//x:root根节点的哈希值
let x = (root.val % MOD + MOD) % MOD
//如果s的左右子树中如果有与t子树相同哈希值的,返回true
if (left === T || right === T) {
res = true
}
//返回:以root为根节点的树的哈希值
return (x + left * P % MOD + right * Q) % MOD
}
};
剑指offer
o33 二叉搜索树的后序遍历序列
/**
* 剑指 Offer 33. 二叉搜索树的后序遍历序列
* 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。
* https://leetcode-cn.com/problems/er-cha-sou-suo-shu-de-hou-xu-bian-li-xu-lie-lcof/
*/
/**
* @param {number[]} postorder
* @return {boolean}
*/
var verifyPostorder = function(postorder) {
let seq = postorder
return dfs(0, seq.length - 1)
// l r当前序列的左右边界
function dfs(l, r) {
if (l >= r) return true
let root = seq[r] // 根节点
// 遍历找右子树的第一个节点
let k = l
while (k < r && seq[k] < root) k ++ // 此时k为右子树第一个节点
// 遍历右子树
for (let i = k; i < r; i ++) {
// 如果右子树节点 < 根节点,返回false
if (seq[i] < root) return false
}
// 继续递归左子树,右子树
return dfs(l, k - 1) && dfs(k, r - 1)
}
};
let num = [7, 4, 6, 5]
console.log(verifyPostorder(num))
o34 二叉树中和为某一值的路径
/**
* 剑指 Offer 34. 二叉树中和为某一值的路径
* 给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
* https://leetcode-cn.com/problems/er-cha-shu-zhong-he-wei-mou-yi-zhi-de-lu-jing-lcof/
*/
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @param {number} target
* @return {number[][]}
*/
var pathSum = function(root, target) {
let res = [], path = []
dfs(root, target)
return res
function dfs(root, sum) {
// 如果当前节点为空,则不是叶子结点
if (! root) return
path.push(root.val)
sum -= root.val // 当sum减到0时,则为所求路径
// 如果当前节点是叶子结点,同时sum=0,该路径加入到res中
// 注意此处要用:path.slice(),以创建一个新数组的方式加入,否则结果是[[]]
if (!root.left && !root.right && !sum) res.push(path.slice())
// 递归遍历左右子树
dfs(root.left, sum)
dfs(root.right, sum)
// 当前路径遍历完成后,恢复现场
path.pop()
}
};
o36 二叉搜索树与双向链表
/**
* 剑指 Offer 36. 二叉搜索树与双向链表
* 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
*/
/**
* // Definition for a Node.
* function Node(val,left,right) {
* this.val = val;
* this.left = left;
* this.right = right;
* };
*/
/**
* @param {Node} root
* @return {Node}
* 思路:中序遍历
*/
var treeToDoublyList = function(root) {
let pre, head
if (!root) return null
dfs(root)
// 遍历完成之后,此时pre指向的是尾结点
// 循环双链表,首尾相连
head.left = pre
pre.right = head
return head
// 二叉搜索树,中序遍历是有序的
function dfs(cur) {
// 当前节点为空,返回
if (!cur) return
// 左子树
dfs(cur.left)
// 处理当前节点 pre:cur的左侧节点
if(pre != null) pre.right = cur;
else head = cur;
cur.left = pre;
pre = cur // pre后移
// 右子树
dfs(cur.right)
}
};