一、题目内容 中等

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

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

  1. 首先找到需要删除的节点;
  2. 如果找到了,删除它。

示例1:

21. 删除二叉搜索树中的节点(450) - 图1 输入:root = [5,3,6,2,4,null,7], key = 3 输出:[5,4,6,2,null,null,7] 解释:给定需要删除的节点值是 3,所以我们首先找到 3 这个节点,然后删除它。 一个正确的答案是 [5,4,6,2,null,null,7], 如下图所示。 另一个正确答案是 [5,2,6,null,4,null,7] 21. 删除二叉搜索树中的节点(450) - 图2

示例2:

输入: root = [5,3,6,2,4,null,7], key = 0 输出: [5,3,6,2,4,null,7] 解释: 二叉树不包含值为 0 的节点

示例3:

输入: root = [], key = 0 输出: []

提示:

  • 节点数的范围 [0, 104].
  • -105 <= Node.val <= 105
  • 节点值唯一
  • root 是合法的二叉搜索树
  • -105 <= key <= 105

二、解题思路

21. 删除二叉搜索树中的节点(450) - 图3
看图说话,要先找到 3。

  1. 从 5 开始,3 < 5,往左子树走
  2. 走到 3,相等。由于 3 的右子树肯定都大于 3,也就都大于 3 的左子树
    1. 所以,把 3 的左子树都放到右子树的最底层左子树
    2. 然后用 3 的右子树代替节点 3,作为 5 的左子树

三、具体代码

  1. const insertLeft = (root, left) => {
  2. while (root.left) root = root.left
  3. root.left = left
  4. }
  5. /**
  6. * @param {TreeNode} root
  7. * @param {number} key
  8. * @return {TreeNode}
  9. */
  10. var deleteNode = function (root, key) {
  11. if (!root) return null
  12. if (root.val < key) root.right = deleteNode(root.right, key)
  13. else if (root.val > key) root.left = deleteNode(root.left, key)
  14. else {
  15. const left = root.left
  16. const right = root.right
  17. if (right) {
  18. insertLeft(right, left)
  19. return right
  20. }
  21. return left
  22. }
  23. return root
  24. };

四、其他解法

  1. const insertLeft = (root, left) => {
  2. while (root.left) root = root.left
  3. root.left = left
  4. }
  5. /**
  6. * @param {TreeNode} root
  7. * @param {number} key
  8. * @return {TreeNode}
  9. */
  10. var deleteNode = function (root, key) {
  11. if (!root) return null
  12. const queue = [root]
  13. let p = null // 记录 node 的父节点
  14. while (queue.length) {
  15. const node = queue.shift()
  16. if (node.val < key) {
  17. if (node.right) queue.push(node.right)
  18. } else if (node.val > key) {
  19. if (node.left) queue.push(node.left)
  20. } else {
  21. let left = node.left
  22. let right = node.right
  23. // 将左子树放到右子树的最底层左子树
  24. if (right) insertLeft(right, left)
  25. else right = left
  26. // 删除节点
  27. if (!p) return right
  28. if (!right) {
  29. if (p.val > key) p.left = null
  30. else p.right = null
  31. } else {
  32. if (p.val > right.val) p.left = right
  33. else p.right = right
  34. }
  35. }
  36. p = node
  37. }
  38. return root
  39. };