跟着卡哥学算法Day 17:二叉树常见题目5
654.最大二叉树 🌟🌟
力扣链接 🌟🌟
题目描述
给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下:
- 二叉树的根是数组中的最大元素。
- 左子树是通过数组中最大值左边部分构造出的最大二叉树。
- 右子树是通过数组中最大值右边部分构造出的最大二叉树。
通过给定的数组构建最大二叉树,并且输出这个树的根节点。
示例 :
输入:[3, 2, 1, 6, 0, 5]
// 输出 树根节点// 6// / \// 3 5// \ /// 2 0// \// 1解题思路
- 关键:构造二叉树一定是前序遍历,先有根节点,递归构造左右子树
递归三部曲:
-
明确递归函数的参数和返回值
- 参数 1:传入的数组
- 返回值:根节点
-
明确终止条件
- 数组长度为 1 时,就是叶子节点,直接构造叶子节点并返回
-
确定单层递归逻辑
-
找最大值和对应下标,值用来构造根节点,下标用来分割数组(左右子树)
let max = nums[0]let maxIndex = 0for (let i = 1; i < nums.length; i++) {if (nums[i] > max) {max = nums[i]maxIndex = i}}const root = new TreeNode(max) -
分割数组
-
用左区间构造左子树
root.left = constructMaximumBinaryTree(nums.slice(0, maxIndex)) -
用右区间构造右子树
root.right = constructMaximumBinaryTree(nums.slice(maxIndex + 1))
-
function constructMaximumBinaryTree(nums) { if (!nums.length) return null
const max = num[0] const maxIndex = 0 for (let i = i; i < nums.length; i++) { if (nums[i] > max) { max = nums[i] maxIndex = i } }
const root = new TreeNode(max) root.left = constructMaximumBinaryTree(nums.slice(0, maxIndex)) root.right = constructMaximumBinaryTree(nums.slice(maxIndex + 1))
return root}617.合并二叉树 🌟
力扣链接 🌟
题目描述
给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。
你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。
示例:
// Tree 1 Tree 2// 1 2// / \ / \// 3 2 1 3// / \ \// 5 4 7
// 合并后// 3// / \// 4 5// /\ \// 5 4 7解题思路
采用前序遍历最直观,与遍历一个树的逻辑一样
递归
递归三部曲:
-
确定递归函数的参数和返回值
- 参数 1:Tree 1
- 参数 2:Tree 2
- 返回值:新二叉树的 root
-
确定终止条件
遍历同一个节点时,Tree 1 为空,返回 Tree 2;Tree 2 为空,返回 Tree 1
if (!root1) return root2if (!root2) return root1 -
确定单层递归逻辑
- 将两个树节点值相加
root.val += root2.val - 递归处理左子树
- 递归处理右子树
- 将两个树节点值相加
function mergeTrees(root1, root2) { if (!root1) return root2 if (!root2) return root1
root1.val += root2.val root1.left = mergeTrees(root1.left, root2.left) root1.right = mergeTrees(root1.right, root2.right)
return root1}迭代
步骤:
- 初始化队列:root1 和 root2 进入队列
- 遍历队列:弹出 root1 和 root2,累加
root1.val += root2.val - 压入左子节点:同时压入 root1.left 和 root2.left,都不为 null 时
- 压入右子节点:同时压入 root1.right 和 root2.right,都不为 null 时
- 注意:如果 root1.left 或 root1.right 为 null 时,直接将 root2.left 或 root2.right 替换为 root1.left 或 root1.right
function mergeTrees(root1, root2) { if (!root1) return root2 if (!root2) return root1
const queue = [root1, root2] while (queue.length) { const node1 = queue.shift() const node2 = queue.shift()
node1.val += node2.val
if (node1.left && node2.left) { queue.push(node1.left) queue.push(node2.left) } if (node1.right && node2.right) { queue.push(node1.right) queue.push(node2.right) } if (!node1.left && node2.left) { node1.left = node2.left } if (!node1.right && node2.right) { node1.right = node2.right } } return root1}700.二叉搜索树中的搜索 🌟
力扣链接 🌟
题目描述
给定二叉搜索树(BST)的根节点和一个值。 你需要在 BST 中找到节点值等于给定值的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 NULL。
示例:
// 给定二叉搜索树:// 4// / \// 2 7// / \// 1 3// 和值:2
// 返回// 2// / \// 1 3解题思路
二叉搜索树:根节点比左子树所有节点的值都大、比右子树所有节点的值都小,同时左右子树都是二叉搜索树
递归
递归三部曲:
-
确定递归函数的参数和返回值
- 参数 1:根节点
- 参数 2:要搜索的值
- 返回值:搜索的值所在的节点
-
确定终止条件
如果 root 为 null 或者找到数值了,返回 root
if (!root || node.val === val) return root -
确定单层递归逻辑
这里与普通二叉树的递归不同
- 若目标值小于当前节点值,递归搜索左子树
- 若目标值大于当前节点值,递归搜索右子树
function searchBST(root, val) { if (!root || root.val === val) return root
if (root.val > val) { return searchBST(root.left, val) } if (root.val < val) { return searchBST(root.right, val) }}迭代
- 使用循环代替递归,从根节点开始遍历
- 根据当前节点值与目标值的比较结果,移动到左子节点或右子节点
- 找到匹配的节点时立即返回,否则遍历结束返回 null
function searchBST(root, val) { while (root) { if (root.val === val) return root
if (root.val > val) { root = root.left } if (root.val < val) { root = root.right } } return root}98.验证二叉搜索树 🌟🌟
力扣链接 🌟🌟
题目描述
给定一个二叉树,判断其是否是一个有效的二叉搜索树。
假设一个二叉搜索树具有如下特征:
- 节点的左子树只包含小于当前节点的数。
- 节点的右子树只包含大于当前节点的数。
- 所有左子树和右子树自身必须也是二叉搜索树。
// 2// / \// 1 3// 输出 true解题思路
常见错误:只比较每个节点与其左右节点的关系,没有考虑全局上节点的关系,如:某个右子树的左节点可能比父节点小,同时比根节点小
需要一个区间[min, max]来确定当前节点值是否在这个区间
递归
三部曲
-
确定递归函数的参数和返回值
- 参数 1:根节点
- 参数 2:最小值,从根节点开始为-Infinity,右子树需要不断更新最小值为当前值
- 参数 3:最大值,从节点为最大值,左子树需要不断更新最大值为当前值
- 返回值:根节点
-
确定终止条件
- 根节点为 null 时,返回 true
- 当前值不在[min, max]区间时,返回 false
-
确定单层递归逻辑
- 递归左右子树
代码
function isValidBST(root) { const traverse = (root, min, max) => { if (!root) return true if (root.val <= min || root.val >= max) return false
return ( traverse(root.left, min, root.val) && traverse(root.right, root.val, max) ) }
return traverse(root, -Infinity, Infinity)}迭代
思路:
- 使用栈存储节点及其允许的上下界
- 遍历时检查节点值是否在范围内,并更新子节点的范围
function isValidBST(root) { if (!root) return true
const stack = [[root, -Infinity, Infinity]]
while (stack.length) { const [node, min, max] = stack.pop() if (node.val <= min || node.val >= max) return false node.left && stack.push([node.left, min, node.val]) node.right && stack.push([node.right, node.val, max]) }
return true}