sl1673495 / leetcode-javascript

:beers: 喝杯小酒,一起做题。前端攻城狮从零入门算法的宝藏题库,根据知名算法老师的经验总结了 100+ 道 LeetCode 力扣的经典题型 JavaScript 题解和思路。已按题目类型分 label,一起加油。

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

删除二叉搜索树中的节点-450

sl1673495 opened this issue · comments

commented

给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的  key  对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。

一般来说,删除节点可分为两个步骤:

首先找到需要删除的节点;
如果找到了,删除它。
说明: 要求算法时间复杂度为  O(h),h 为树的高度。

示例:

root = [5,3,6,2,4,null,7]
key = 3

    5
   / \
  3   6
 / \   \
2   4   7

给定需要删除的节点值是 3,所以我们首先找到 3 这个节点,然后删除它。

一个正确的答案是 [5,4,6,2,null,null,7], 如下图所示。

    5
   / \
  4   6
 /     \
2       7

另一个正确答案是 [5,2,6,null,4,null,7]。

    5
   / \
  2   6
   \   \
    4   7

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/delete-node-in-a-bst
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

这题我的思路是这样的,先通过递归去找到目标节点的 父节点 parent,和目标节点的位置 posleftright,方便后续删除操作。

  1. 待删除节点没有 left或者 right 子节点的情况下,直接吧 parent[pos] = null 清空即可。
  2. 待删除节点只有 left 或只有 right,那就把 parent[pos] 赋值为存在的那个子节点即可。
  3. 如果 leftright 都在的情况下,比较复杂一些,把待删除节点的左右子节点分别称为 targetLefttargetRight,先找到targetRight的最左子节点,这个子节点一定在右子树中最小,但是在左子树中最大。然后把 parent[pos] 赋值为 targetRight,再把 targetRight的最左下角子节点的 left 赋值成原来的 targetLeft 即可。
let deleteNode = function (root, key) {
  let findNodePos = (node, key) => {
    if (!node) {
      return false
    }
    if (node.left && node.left.val === key) {
      return {
        parent: node,
        pos: "left",
      }
    } else if (node.right && node.right.val === key) {
      return {
        parent: node,
        pos: "right",
      }
    } else {
      return findNodePos(node.left, key) || findNodePos(node.right, key)
    }
  }

  let findLastLeft = (node) => {
    if (!node.left) {
      return node
    }
    return findLastLeft(node.left)
  }

  let virtual = new TreeNode()
  virtual.left = root

  let finded = findNodePos(virtual, key)
  if (finded) {
    let { parent, pos } = finded
    let target = parent[pos]
    let targetLeft = target.left
    let targetRight = target.right

    if (!targetLeft && !targetRight) {
      parent[pos] = null
    } else if (!targetRight) {
      parent[pos] = targetLeft
    } else if (!targetLeft) {
      parent[pos] = targetRight
    } else {
      parent[pos] = targetRight
      let lastLeft = findLastLeft(targetRight)
      lastLeft.left = targetLeft
    }
  }

  return virtual.left
}