跟着卡哥学算法Day 21:二叉树常见题目8

1667 字
8 分钟
跟着卡哥学算法Day 21:二叉树常见题目8

669. 修剪二叉搜索树 🌟🌟#

力扣链接 🌟🌟

题目描述#

给定一个二叉搜索树,同时给定最小边界 L 和最大边界 R。通过修剪二叉搜索树,使得所有节点的值在[L, R]中 (R>=L) 。你可能需要改变树的根节点,所以结果应当返回修剪好的二叉搜索树的新的根节点。

示例 1:

binary-tree-node-trim
binary-tree-node-trim

示例 2:

binary-tree-node-trim1
binary-tree-node-trim1

解题思路#

修剪二叉搜索树的关键:当某个节点的值不在范围内时,应该如何调整其子树,使得调整后的树仍然保持 BST 的结构

递归#

  • 当前节点值小于 low,其左子树的所有节点值更小,都不在范围内,这时候递归处理右子树,并返回处理后的节点作为当前节点
  • 当前节点值大于 high,其右子树的所有节点值更大,都不在范围内,递归处理左子树,并返回处理后的节点作为当前节点
  • 当前节点值在 low 和 high 之间时,需要同时处理左右子树,并将处理后的节点作为当前节点的左右孩子

递归三部曲:

  1. 明确递归函数的参数和返回值

    • 参数 1:当前节点
    • 参数 2:low
    • 参数 3:high
    • 返回值:处理后的节点
  2. 明确终止条件

    • 当节点为 null 返回 null
  3. 确定单层递归逻辑

    • node.val < low,左子树都小于 low,递归处理右子树

      if (node.val < low) {
      return trimBST(root.right, low, high)
      }
    • node.val > high,右子树都大于 high,递归处理左子树

      if (node.val > high) {
      return trimBST(root.left, low, high)
      }
    • 否则,node.val 在范围内,递归左右子树

      node.left = trimBST(root.left, low, high)
      node.right = trimBST(root.right, low, high)
      return node
function trimBST(root, low, high) {
if (!root) return null
if (root.val < low) {
return trimBST(root.right, low, high)
}
if (root.val > high) {
return trimBST(root.left, low, high)
}
root.left = trimBST(root.left, low, high)
root.right = trimBST(root.right, low, high)
return root
}

迭代#

迭代方法通过队列遍历所有节点,逐步调整结构:

  1. 调整根节点:找到第一个符合范围的节点作为新根。
  2. 层序处理每个节点
    • 处理左子节点:若左子节点的值小于 low,则用其右子树替换,直到符合条件。
    • 处理右子节点:若右子节点的值大于 high,则用其左子树替换,直到符合条件。
function trimBST(root, low, high) {
// 1. 调整根节点
while (root && (root.val < low || root.val > high)) {
root = root.val < low ? root.right : root.left
}
if (!root) return null
// 2. 层序遍历处理所有节点
const queue = [root]
while (queue.length) {
const node = queue.shift()
// 处理左子节点
while (node.left && node.left.val < low) {
node.left = node.left.right
}
if (node.left) queue.push(node.left)
// 处理右子节点
while (node.right && node.right.val > high) {
node.right = node.right.left
}
if (node.right) queue.push(node.right)
}
return root
}

108.将有序数组转换为二叉搜索树 🌟#

力扣链接 🌟

题目描述#

将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。

本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。

sort-array-to-bst
sort-array-to-bst

解题思路#

升序数组:二叉搜索树的中序遍历结果就是一个升序数组

利用升序数组构造二叉搜索树#

不能随便选节点作为根,而是需要让左右子树的节点数尽可能接近,这样高度差才会小

如:[-10, -3, 0, 5, 9]

  • 数字长度为奇数,中间元素为 0,作为根节点,左右各两个节点[-10, -3]

  • 此时左右节点长度为偶数,根节点选择中间任何一个节点都可以

    // 例如4个元素,索引是0到3
    // 中间位置的计算是(0+3)/2=1.5
    // Math.floor得到1,所以mid=1
    // 或Math.ceil的话得到2
    // 这两种取法都会导致不同的树结构,但都是平衡的

递归#

递归三部曲:

  1. 确定递归函数的参数和返回值

    • 参数 1:有序数组
    • 参数 2:left 区间
    • 参数 3:right 区间
    • 返回值:树节点(用于构造中节点的左右孩子)
  2. 确定终止条件

    当左区间 left>右区间 right 时,就是空节点

    if (left > right) return null
  3. 确定单层递归逻辑

    • 取中间节点 const mid = left + ((right - left) / 2)
    • 构造树节点 const root = new TreeNode(nums[mid])
    • 根据区间,继续构造左右子树
function sortedArrayToBST(nums) {
const buildTree = (nums, left, right) => {
if (left > right) return null
const mid = Math.floor(left + (right - left) / 2)
const root = new TreeNode(nums[mid])
root.left = buildTree(nums, left, mid - 1)
root.right = buildTree(nums, mid + 1, right)
return root
}
return buildTree(nums, 0, nums.length - 1)
}

538.把二叉搜索树转换为累加树 🌟🌟#

力扣链接 🌟🌟

题目描述#

给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。

提醒一下,二叉搜索树满足下列约束条件:

节点的左子树仅包含键 小于 节点键的节点。 节点的右子树仅包含键 大于 节点键的节点。 左右子树也必须是二叉搜索树。

示例 1:

convert-BST
convert-BST

提示:

  • 树中的节点数介于 0 和 104 之间。
  • 每个节点的值介于 -104 和 104 之间。
  • 树中的所有值 互不相同 。
  • 给定的树为二叉搜索树。

解题思路#

累加树:每个节点的值变成该树中所有大于或等于该节点值的总和

  • 因此,应该从最大的节点开始累加
  • 二叉搜索树,最右侧的节点是最大的
  • 逆中序遍历:右 -> 中 -> 左

递归#

递归三部曲:

  1. 确定递归函数的参数和返回值

    • 参数 1:根节点
    • 返回值:不需要
  2. 确定终止条件

    遇到空节点终止,返回

    if (!root) return
  3. 确定单层递归逻辑

    • 右 -> 中 -> 左顺序
    • 中节点处理逻辑:root.val += sum
function convertBST(root) {
let sum = 0
const traverse = (root) => {
if (!root) return
root.right && traverse(root.right)
sum += root.val
root.val = sum
root.left && traverse(root.left)
}
traverse(root)
return root
}

迭代#

步骤解析:

  • 栈模拟遍历:用栈实现反向中序遍历。
  • 循环处理右子树:先将所有右子节点压入栈中,再逐个处理并转向左子树。
const convertBST = function (root) {
let sum = 0
let stack = []
let curr = root
while (curr || stack.length) {
// 将当前节点的所有右子节点入栈
while (curr) {
stack.push(curr)
curr = curr.right
}
curr = stack.pop() // 处理当前节点
sum += curr.val
curr.val = sum
curr = curr.left // 转向左子树
}
return root
}
跟着卡哥学算法Day 21:二叉树常见题目8
https://wangxiang.website/posts/算法/binary-tree-code7/
作者
翔子
发布于
2025-03-04
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
翔子
前端开发工程师
公告
博客已从 VitePress 迁移到 Astro + Firefly 主题,223 篇文章全部保留。
音乐
封面

音乐

暂未播放

0:00 0:00
暂无歌词
分类
标签
站点统计
文章
221
分类
9
标签
28
总字数
411,914
运行时长
0
最后活动
0 天前

文章目录