树的简介
「树」的特点是:除了根结点以外,其它结点都有唯一的父亲结点。「树」还可以递归定义:
- 树是有限结点的集合;
- 这个集合或者是空集,或者其中有一个称为根结点的特殊结点,其余结点分别属于 不同 的 不相交 的树,这些树分别是原始树(或称作原始树的根结点)的子树。
很多树的问题都可以使用「递归」方法解决。树形结构还有一个重要的特征区别于其它复杂的数据结构的特点:在树形结构里,能看到非常明显的 层次结构,用于表示各种常见的 层次 关系。
二叉树
二叉树是最简单的树形结构:如果一棵树中每个结点 至多 有两个孩子结点,这样的树就称为二叉树。 孩子结点与父亲结点之间的连接像极了树的分叉,因此叫做二叉树。 二叉树的结点如果有孩子结点的话,使用 左结点 和 右结点 来区分。类似可以定义多叉树:如果一棵树任意结点最多含有的结点数为 N,这棵树就是 N 叉树。
- 一个结点、空结点、单链表也是二叉树,因为它们都符合二叉树的定义;
- 一般而言,二叉树的两个孩子结点会规定次序,如果两个都有的话,分为左孩子和右孩子。如果只有一个孩子结点,可以只有左孩子结点,也可以只有右孩子结点。
完全二叉树与满二叉树
完全二叉树 :从形态上看完全二叉树是个 只缺了最后一行右边 的的三角形。即:完全二叉树所有的结点按照从上到下、从左到右紧凑摆放,中间不会有缺失结点。堆 就是完全二叉树的样子。
满二叉树:满二叉树首先是完全二叉树。其次,从形态上看,满二叉树是一个没有缺角的三角形,即每一层结点的个数都达到了这一层能达到的最大结点数。
二叉树的遍历
通过 一定的顺序 访问二叉树的 所有 结点。树的遍历有 深度优先遍历 (Depth First Search) 和 广度优先遍历(Breadth First Search) ,其中深度优先遍历又分为前序遍历 、中序遍历 、后序遍历。
练习
二叉树的层序遍历 - 中等
js
/**
* 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) {
const res = [];
if (root === null) return res;
const queue = [root];
while (queue.length) {
const curLevel = [];
const curSize = queue.length;
for (let i = 0; i < curSize; i++) {
const cur = queue.shift();
curLevel.push(cur.val);
if (cur.left != null) {
queue.push(cur.left);
}
if (cur.right != null) {
queue.push(cur.right);
}
}
res.push(curLevel);
}
return res;
};
二叉树的层次遍历 II - 中等
js
/**
* 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 levelOrderBottom = function (root) {
const res = [];
if (root === null) return res;
const queue = [root];
while (queue.length) {
const curLevel = [];
const n = queue.length;
for (let i = 0; i < n; i++) {
const cur = queue.shift();
curLevel.push(cur.val);
if (cur.left) {
queue.push(cur.left);
}
if (cur.right) {
queue.push(cur.right);
}
}
res.push(curLevel);
}
return res.reverse();
};
二叉树的锯齿形层次遍历 - 中等
js
/**
* 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) {
const res = [];
if (root === null) return res;
const queue = [root];
while (queue.length) {
const curLevel = [];
const n = queue.length;
for (let i = 0; i < n; i++) {
const cur = queue.shift();
curLevel.push(cur.val);
if (cur.left) queue.push(cur.left);
if (cur.right) queue.push(cur.right);
}
res.push(res.length % 2 ? curLevel.reverse() : curLevel);
}
return res;
};
二叉树的前序遍历 - 简单
js
/**
* 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 preorderTraversal = function (root) {
const res = [];
if (root === null) return res;
const stack = [root];
while (stack.length) {
const cur = stack.pop();
res.push(cur.val);
if (cur.right) stack.push(cur.right);
if (cur.left) stack.push(cur.left);
}
return res;
};
二叉树的中序遍历 - 简单
js
/**
* 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 inorderTraversal = function (root) {
const res = [];
const stack = [];
let cur = root;
while (cur !== null || stack.length > 0) {
// 将所有的左子节点压入栈中
while (cur !== null) {
stack.push(cur);
cur = cur.left;
}
// 当前节点为空,表明已经到达左子树的最左边
cur = stack.pop();
res.push(cur.val); // 访问当前节点
// 转向右子节点
cur = cur.right;
}
return res;
};
二叉树的后序遍历 - 简单
js
/**
* 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 postorderTraversal = function (root) {
const res = [];
if (root === null) return res;
const find = (tree) => {
if (tree.left) find(tree.left);
if (tree.right) find(tree.right);
res.push(tree.val);
};
find(root);
return res;
};
二叉树的最小深度 - 简单
js
/**
* 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 minDepth = function (root) {
let min = Number.MAX_SAFE_INTEGER;
if (root === null) return 0;
const findDeep = (tree, deep) => {
// 到达叶子节点
if (!tree.left && !tree.right) {
min = Math.min(min, deep);
}
if (tree.left) {
findDeep(tree.left, deep + 1);
}
if (tree.right) {
findDeep(tree.right, deep + 1);
}
};
findDeep(root, 1);
return min;
};
路径总和 - 简单
js
/**
* 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} targetSum
* @return {boolean}
*/
var hasPathSum = function (root, targetSum) {
if (root === null) return false;
let result = false;
const findTotal = (tree, total) => {
if (result) return;
total += tree.val;
// 叶子节点
if (!tree.left && !tree.right) {
result = result || total === targetSum;
}
if (tree.left) {
findTotal(tree.left, total);
}
if (tree.right) {
findTotal(tree.right, total);
}
};
findTotal(root, 0);
return result;
};
求根到叶子节点数字之和 - 中等
js
/**
* 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 sumNumbers = function (root) {
const res = [];
if (root === null) return 0;
const find = (tree, arr) => {
arr.push(tree.val);
if (!tree.left && !tree.right) {
res.push(arr);
}
if (tree.left) find(tree.left, [...arr]);
if (tree.right) find(tree.right, [...arr]);
};
find(root, []);
return res.reduce((total, el) => {
return total + Number(el.join(""));
}, 0);
};
相同的树 - 简单
js
/**
* 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} p
* @param {TreeNode} q
* @return {boolean}
*/
var isSameTree = function (p, q) {
let same = true;
const isSame = (p, q) => {
if (!same) return;
if (!p && !q) return;
if ((p && !q) || (!p && q)) {
same = false;
return;
}
if (p.val !== q.val) {
same = false;
return;
}
isSame(p.left, q.left);
isSame(p.right, q.right);
};
isSame(p, q);
return same;
};
完全二叉树的节点个数 - 简单
js
/**
* 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 countNodes = function (root) {
let count = 0;
if (root === null) return 0;
const find = (tree) => {
count += 1;
if (tree.left) find(tree.left);
if (tree.right) find(tree.right);
};
find(root);
return count;
};
对称二叉树 - 简单
js
/**
* 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) {
let same = true;
const isSame = (left, right) => {
if ((!left && !right) || !same) return;
if ((!left && right) || (left && !right)) {
same = false;
return;
}
if (left.val !== right.val) {
same = false;
return;
}
isSame(left.left, right.right);
isSame(left.right, right.left);
};
isSame(root.left, root.right);
return same;
};
二叉树中的最大路径和 - 困难
js
/**
* 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 maxPathSum = function (root) {
let max = Number.MIN_SAFE_INTEGER;
if (root === null) return 0;
const find = (tree) => {
if (tree === null) return 0;
const left = find(tree.left);
const right = find(tree.right);
max = Math.max(max, tree.val + left + right);
return Math.max(tree.val + Math.max(left, right), 0);
};
find(root);
return max;
};
翻转二叉树 - 简单
js
/**
* 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 {TreeNode}
*/
var invertTree = function (root) {
const reverse = (tree) => {
if (tree === null) return tree;
const temp = tree.left;
tree.left = tree.right;
tree.right = temp;
reverse(tree.left);
reverse(tree.right);
return tree;
};
return reverse(root);
};
平衡二叉树 - 简单
js
/**
* 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 isBalanced = function (root) {
let res = true;
if (root === null) return res;
const find = (tree) => {
if (!res) return 0;
if (tree === null) return 0;
const leftDeep = find(tree.left);
const rightDeep = find(tree.right);
if (Math.abs(leftDeep - rightDeep) > 1) {
res = false;
}
return Math.max(leftDeep, rightDeep) + 1;
};
find(root);
return res;
};
经典问题:从前、中序遍历序列构造二叉树
从前序与中序遍历序列构造二叉树 - 中等
js
/**
* 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}
*/
function buildTree(preorder, inorder) {
if (!preorder.length || !inorder.length) {
return null;
}
// 前序遍历的第一个元素是根节点
const rootVal = preorder[0];
const root = new TreeNode(rootVal);
// 在中序遍历中找到根节点的位置
const rootIndex = inorder.indexOf(rootVal);
// 递归构造左子树和右子树
root.left = buildTree(
preorder.slice(1, rootIndex + 1),
inorder.slice(0, rootIndex)
);
root.right = buildTree(
preorder.slice(rootIndex + 1),
inorder.slice(rootIndex + 1)
);
return root;
}
从中序与后序遍历序列构造二叉树 - 中等
js
/**
* 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[]} inorder
* @param {number[]} postorder
* @return {TreeNode}
*/
var buildTree = function (inorder, postorder) {
if (!inorder.length || !postorder.length) return null;
const head = postorder.at(-1);
const root = new TreeNode(head);
const index = inorder.indexOf(head);
root.left = buildTree(
inorder.slice(0, index),
postorder.slice(0, inorder.slice(0, index).length)
);
root.right = buildTree(
inorder.slice(index + 1),
postorder.slice(inorder.slice(0, index).length, -1)
);
return root;
};
典型问题:二叉树的最近公共祖先
二叉树的最近公共祖先 - 中等
js
/**
* 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 === null || root === p || root === q) return root;
const left = lowestCommonAncestor(root.left, p, q);
const right = lowestCommonAncestor(root.right, p, q);
if (left != null && right != null) {
return root;
}
if (left === null) {
return right;
}
return left;
};
二叉树的序列化与反序列化 - 困难
js
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* Encodes a tree to a single string.
*
* @param {TreeNode} root
* @return {string}
*/
var serialize = function (root) {
if (root === null) return "";
const nextOrder = [];
const midOrder = [];
let id = 0;
const map = new Map();
const find = (tree, type) => {
if (tree === null) return null;
if (!map.has(tree)) {
map.set(tree, id++);
}
if (type === 1) {
find(tree.left, 1);
find(tree.right, 1);
nextOrder.push(`${map.get(tree)}:${tree.val}`);
} else {
find(tree.left, 2);
midOrder.push(`${map.get(tree)}:${tree.val}`);
find(tree.right, 2);
}
};
find(root, 1);
find(root, 2);
return nextOrder.join(".") + "|" + midOrder.join(".");
};
/**
* Decodes your encoded data to tree.
*
* @param {string} data
* @return {TreeNode}
*/
var deserialize = function (data) {
if (data === "") return null;
const arr = data.split("|");
const nextOrder = arr[0].split(".").map((el) => {
const [id, val] = el.split(":").map(Number);
return { id, val };
});
const midOrder = arr[1].split(".").map((el) => {
const [id, val] = el.split(":").map(Number);
return { id, val };
});
const build = (mid, next) => {
if (!mid.length || !next.length) return null;
const { id, val } = next.pop();
const tree = new TreeNode(val);
const index = mid.findIndex((node) => node.id === id);
tree.left = build(mid.slice(0, index), next.slice(0, index));
tree.right = build(mid.slice(index + 1), next.slice(index));
return tree;
};
const root = build(midOrder, nextOrder);
return root;
};
二叉树的直径 - 简单
js
/**
* 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 diameterOfBinaryTree = function (root) {
if (root === null) return 0;
let max = 0;
const find = (tree) => {
if (tree === null) return 0;
const left = find(tree.left);
const right = find(tree.right);
// 更新最大直径
max = Math.max(left + right, max);
// 返回树的高度
return Math.max(left, right) + 1;
};
find(root);
return max;
};
收集树上所有苹果的最少时间 - 中等
js
/**
* @param {number} n
* @param {number[][]} edges
* @param {boolean[]} hasApple
* @return {number}
*/
var minTime = function (n, edges, hasApple) {
// 构建图的邻接表表示
const graph = new Array(n).fill(0).map(() => []);
for (const [from, to] of edges) {
graph[from].push(to);
graph[to].push(from);
}
// DFS函数,返回从当前节点出发收集所有苹果所需的时间
const dfs = (node, parent) => {
let time = 0;
for (const neighbor of graph[node]) {
if (neighbor === parent) continue; // 避免回到父节点
const childTime = dfs(neighbor, node);
if (childTime > 0 || hasApple[neighbor]) {
time += childTime + 2; // 往返邻居节点的时间
}
}
return time;
};
return dfs(0, -1);
};
二叉搜索树
二叉搜索树还可以通过 递归 的方式定义:
- 二叉搜索树可以是一棵空树;
- 二叉搜索树由根结点,左子树和右子树组成,其中左子树和右子树都是二叉搜索树,并且左子树上所有结点的键值 小于 根结点的键值,并且右子树上所有结点的键值 大于 根结点的键值。
根据二叉搜索树的定义得到的性质 由二叉搜索树的定义和中序遍历的定义得到:二叉搜索树中序遍历得到的序列是有序的。
通过具体例子理解二叉搜索树是如何组织数据
在有序数组里查找元素可以使用二分查找算法,看到了一个元素的值,和目标元素比较:
- 如果找到了这个元素,进行相关操作;
- 如果目标元素的值 小于 当前看到的元素值,继续向左边查找;
- 如果目标元素的值 大于 当前看到的元素值,继续向右边查找。
二叉搜索树的定义保证了键的有序,向二叉搜索树中插入元素,首先需要查找到插入元素的位置。查找的时候使用类似二分查找的思路:从根结点开始,通过比较 键 决定向左走还是向右走,直到来到叶子结点,即:每次选择子树中的一半,跳过另一半,这是减治思想的应用。
二叉搜索树查找元素与插入元素是类似的逻辑:在插入元素的时候,意识地维护了有序性,进而在查找元素的时候,可以根据 有序性 查找元素,时间复杂度为 O(logN),这里N 是树结点的个数,logN 是树的高度的近似值。
删除二叉搜索树中的结点 - 中等
js
/**
* 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} key
* @return {TreeNode}
*/
var deleteNode = function (root, key) {
if (root === null) return null;
if (root.val > key) {
root.left = deleteNode(root.left, key);
return root;
} else if (root.val < key) {
root.right = deleteNode(root.right, key);
return root;
// 当前节点 = key
} else {
// 左子树为空,则右子树成为当前节点
if (root.left === null) {
return root.right;
}
// 右子树为空,则左子树成为当前节点
if (root.right === null) {
return root.left;
}
// 当前节点存在左右子树时,使用前驱节点代替当前节点
const successor = findMax(root.left); // 前驱节点
successor.left = removeMax(root.left);
successor.right = root.right;
return successor;
}
};
const removeMax = (root) => {
if (root.right === null) {
return root.left;
}
root.right = removeMax(root.right);
return root;
};
const findMax = (root) => {
if (root.right === null) {
return root;
}
return findMax(root.right);
};
二叉搜索树中的搜索 - 简单
js
/**
* 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} val
* @return {TreeNode}
*/
var searchBST = function (root, val) {
if (root === null) return null;
if (root.val > val) {
return searchBST(root.left, val);
} else if (root.val < val) {
return searchBST(root.right, val);
} else {
return root;
}
};
二叉搜索树中的插入操作 - 中等
js
/**
* 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} val
* @return {TreeNode}
*/
var insertIntoBST = function (root, val) {
if (root === null) return new TreeNode(val);
if (root.val > val) {
root.left = insertIntoBST(root.left, val);
} else {
root.right = insertIntoBST(root.right, val);
}
return root;
};
二叉搜索树迭代器 - 中等
js
/**
* 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
*/
var BSTIterator = function (root) {
this.root = root;
this.list = [];
this.index = 0;
this.find(root);
console.log(this.list);
return null;
};
/**
* @return {number}
*/
BSTIterator.prototype.next = function () {
if (this.index >= this.list.length) return null;
const result = this.list[this.index];
this.index++;
return result;
};
/**
* @return {boolean}
*/
BSTIterator.prototype.hasNext = function () {
return this.index <= this.list.length - 1;
};
/**
* @return {number}
*/
BSTIterator.prototype.find = function (root) {
if (root === null) return;
if (root.left) this.find(root.left);
this.list.push(root.val);
if (root.right) this.find(root.right);
};
/**
* Your BSTIterator object will be instantiated and called as such:
* var obj = new BSTIterator(root)
* var param_1 = obj.next()
* var param_2 = obj.hasNext()
*/
序列化和反序列化二叉搜索树 - 困难
js
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* Encodes a tree to a single string.
*
* @param {TreeNode} root
* @return {string}
*/
var serialize = function (root) {
if (root === null) return "";
const data = [];
// 前序遍历
function pre(tree) {
if (tree === null) return null;
data.push(tree.val);
if (tree.left) pre(tree.left);
if (tree.right) pre(tree.right);
}
pre(root);
return data.join("|");
};
/**
* Decodes your encoded data to tree.
*
* @param {string} data
* @return {TreeNode}
*/
var deserialize = function (data) {
if (data === "") return null;
const preL = data.split("|");
const midL = [...preL].sort((a, b) => a - b);
function build(pre, mid) {
if (!pre.length && !mid.length) return null;
const head = pre.shift(); // 头节点
const idx = mid.indexOf(head);
const tree = new TreeNode(head);
if (pre.length) {
tree.left = build(pre.slice(0, idx), mid.slice(0, idx));
}
if (mid.length) {
tree.right = build(pre.slice(idx), mid.slice(idx + 1));
}
return tree;
}
const root = build(preL, midL);
return root;
};
将有序数组转换为二叉搜索树 - 简单
js
/**
* 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) {
const len = nums.length;
if (!len) return null;
const buildBST = (left, right) => {
if (left > right) return null;
const mid = left + Math.floor((right - left) / 2); // 当前头节点
const root = new TreeNode(nums[mid]);
root.left = buildBST(left, mid - 1);
root.right = buildBST(mid + 1, right);
return root;
};
return buildBST(0, len - 1);
};
有序链表转换二叉搜索树 - 中等
js
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* 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 {ListNode} head
* @return {TreeNode}
*/
var sortedListToBST = function (head) {
if (head === null) return null;
const len = getLen(head); // 链表长度
this.head = head;
return buildBST.apply(this, [0, len - 1]);
};
function buildBST(left, right) {
if (left > right) return null;
const mid = left + Math.floor((right - left) / 2);
const tree = new TreeNode();
tree.left = buildBST.apply(this, [left, mid - 1]);
tree.val = this.head.val;
this.head = this.head.next;
tree.right = buildBST.apply(this, [mid + 1, right]);
return tree;
}
const getLen = (head) => {
let count = 0;
while (head) {
count++;
head = head.next;
}
return count;
};
二叉搜索树的最近公共祖先 - 中等
js
/**
* 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 === null) return null;
const find = (tree) => {
if (tree === null) return null;
tree.left = find(tree.left);
tree.right = find(tree.right);
if (tree.val === p.val || tree.val === q.val) return tree;
if (tree.left && tree.right) {
} else if (tree.left) {
tree = tree.left;
} else {
tree = tree.right;
}
return tree;
};
console.log(find(root));
return find(root);
};
把二叉搜索树转换为累加树 - 中等
js
/**
* 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 {TreeNode}
*/
var convertBST = function (root) {
let sum = 0;
const add = (tree) => {
if (tree != null) {
add(tree.right);
sum += tree.val;
tree.val = sum;
add(tree.left);
}
return tree;
};
add(root);
return root;
};
两数之和 IV - 输入 BST - 简单
js
/**
* 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} k
* @return {boolean}
*/
var findTarget = function (root, k) {
if (root === null) return false;
const list = [];
const find = (tree) => {
if (tree.left) find(tree.left);
list.push(tree.val);
if (tree.right) find(tree.right);
};
find(root);
if (list.length <= 1) return false;
for (let i = 0; i < list.length - 1; i++) {
for (let j = i + 1; j < list.length; j++) {
if (list[i] + list[j] === k) return true;
}
}
return false;
};
典型问题:二叉搜索树中第 K 小的元素
二叉搜索树中第 K 小的元素 - 中等
js
/**
* 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} k
* @return {number}
*/
var kthSmallest = function (root, k) {
let count = k;
let res;
// 中序遍历二叉搜索树,得到的是升序的数组
const find = (tree) => {
if (tree === null) return null;
find(tree.left);
count--;
if (count === 0) {
res = tree.val;
return;
}
find(tree.right);
};
find(root);
return res;
};
修剪二叉搜索树 - 中等
js
/**
* 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} low
* @param {number} high
* @return {TreeNode}
*/
var trimBST = function (root, low, high) {
// 中序遍历
const find = (tree) => {
if (tree === null) return null;
if (tree?.left) tree.left = find(tree.left);
if (tree.val < low) {
tree = find(tree.right);
} else if (tree.val > high) {
tree = find(tree.left);
}
if (tree?.right) tree.right = find(tree.right);
return tree;
};
return find(root);
};
二叉搜索树节点最小距离 - 中等
js
/**
* 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} low
* @param {number} high
* @return {TreeNode}
*/
var trimBST = function (root, low, high) {
// 中序遍历
const find = (tree) => {
if (tree === null) return null;
if (tree?.left) tree.left = find(tree.left);
if (tree.val < low) {
tree = find(tree.right);
} else if (tree.val > high) {
tree = find(tree.left);
}
if (tree?.right) tree.right = find(tree.right);
return tree;
};
return find(root);
};
两棵二叉搜索树中的所有元素 - 中等
js
/**
* 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} root1
* @param {TreeNode} root2
* @return {number[]}
*/
var getAllElements = function (root1, root2) {
const r1 = [];
function find(tree) {
if (tree === null) return;
if (tree?.left) find(tree.left);
r1.push(tree.val);
if (tree?.right) find(tree.right);
}
find(root1);
const r2 = [];
function find2(tree) {
if (tree === null) return;
if (tree?.left) find2(tree.left);
r2.push(tree.val);
if (tree?.right) find2(tree.right);
}
find2(root2);
return r1.concat(r2).sort((a, b) => a - b);
};
典型问题:验证二叉搜索树
验证二叉搜索树 - 中等
js
/**
* 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 isValidBST = function (root) {
let prev;
let result = true;
const find = (tree) => {
if (tree === null) return;
if (tree.left) find(tree.left);
if (prev && result) {
result = tree.val > prev.val ? true : false;
}
prev = tree;
if (tree.right) find(tree.right);
};
find(root);
return result;
};
二叉搜索子树的最大键值和 - 困难
js
/**
* 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 maxSumBST = function (root) {
if (root === null) return 0;
let res = Number.MIN_SAFE_INTEGER;
// 采用后序遍历
// 先判断左子树是否为二叉搜索树,判断右子树是否为二叉搜索树
// 再判断左子树.val是否小于当前val,判断右子树.val是否大于.val
// 符合条件则累加起来
const dfs = (tree) => {
if (tree === null) return null;
tree.left = dfs(tree.left);
tree.right = dfs(tree.right);
if (tree.left && tree.right) {
if (tree.val > tree.left.max && tree.val < tree.right.min) {
tree.total = tree.val + tree.left.total + tree.right.total;
tree.isBST = true;
tree.min = tree.left.min;
tree.max = tree.right.max;
}
} else if (tree.left && !tree.right) {
if (tree.left.isBST && tree.left.max < tree.val) {
tree.total = tree.val + tree.left.total;
tree.isBST = true;
tree.min = tree.left.min;
tree.max = tree.val;
}
} else if (!tree.left && tree.right) {
if (tree.right.isBST && tree.val < tree.right.min) {
tree.total = tree.val + tree.right.total;
tree.isBST = true;
tree.min = tree.val;
tree.max = tree.right.max;
}
} else {
tree.total = tree.val;
tree.isBST = true;
tree.min = tree.val;
tree.max = tree.val;
}
if (tree.total) {
res = Math.max(tree.total, res);
}
return tree;
};
dfs(root);
return res < 0 ? 0 : res;
};