> 文章列表 > 代码随想录-67-450. 删除二叉搜索树中的节点

代码随想录-67-450. 删除二叉搜索树中的节点

代码随想录-67-450. 删除二叉搜索树中的节点

目录

  • 前言
    • 题目
    • 1.二叉搜索树特性递归找到要删除的节点
    • 2. 本题思路分析:
    • 3. 算法实现
    • 4. 算法坑点

前言

我在刷卡哥的“代码随想录”,自己的总结笔记均会放在“算法刷题-代码随想录”该专栏下。
代码随想录此题链接

题目

代码随想录-67-450. 删除二叉搜索树中的节点
代码随想录-67-450. 删除二叉搜索树中的节点
代码随想录-67-450. 删除二叉搜索树中的节点

1.二叉搜索树特性递归找到要删除的节点

按照二叉搜索树特性递归。

2. 本题思路分析:

递归三部曲:

  1. 参数与返回值:
  • 参数:当前节点cur和需要删除节点的值val
  • 返回值:返回TreeNode类型对象
  1. 终止条件:当前节点为null,说明没找到了需要删除的节点,则null即可。
  2. 单层循环逻辑:
  • 如果当前节点的值大于需要删除节点的值,则递归时用左孩子代入,并且递归函数的返回值用当前节点的左孩子接收;
  • 如果当前节点的值小于需要删除节点的值,则递归时用右子树代入,并且递归函数的返回值用当前节点的右子树接收;
  • 返回当前节点的值等于需要删除节点的值,就要删除当前节点,删除节点还有4种情况。
      1. 该节点左右孩子均为null,说明此为叶子节点。直接返回null。(因为递归函数的返回值会有对应左右孩子接收,在java中的删除,相当于父节点对应的左(右)孩子指针从指向本节点到指向null,本节点就找不到了,相当于就被删除了)
      1. 该节点右孩子为空,则说明左孩子不为空(因为第一种情况已经包括了左右孩子均为空的情况),则直接返回左孩子。因为相当于当前节点的左孩子替代了当前节点。(递归函数就是当前节点的父节点的左(右)孩子(也就是当前节点本身)接收,递归函数的参数也是当前节点的父节点的左(右)孩子(也就是当前节点本身),返回当前节点的左孩子,则相当于让当前节点的父节点的左孩子(当前节点的指针)指向了当前节点的左孩子,用当前节点的左孩子替换了当前节点,就相当于把当前节点删除。)
      1. 该节点左孩子为空,则说明右孩子不为空(因为第一种情况已经包括了左右孩子均为空的情况),则直接返回右孩子。分析同第2个。
      1. 改节点左右孩子均不为null。这个稍复杂,就是按照二叉搜索树的性质,当前节点的左子树中的所有节点一定比当前节点右子树中最小的节点还要小。所以应该把左子树放到右子树中最左边的叶子节点的左孩子位置,并且用当前节点的右孩子替换当前节点

3. 算法实现

class Solution {public TreeNode deleteNode(TreeNode root, int key) {if(root == null){return null;}if(root.val == key){if(root.left == null && root.right == null){return null;}else if(root.right == null){return root.left;}else if(root.left == null){return root.right;}else{TreeNode cur = root.right;while(cur.left != null){cur = cur.left;}cur.left = root.left;return root.right;}}else if(root.val > key){root.left = deleteNode(root.left, key);}else if(root.val < key){root.right = deleteNode(root.right, key);}return root;}
}

4. 算法坑点

  1. 本题,当终止条件(cur==null)时,说明在该二叉搜索树上并没有找到了要删除节点,此时直接返回null即可。
  2. 当前节点大于要插入节点的值,表明此时在向左子树中寻找要删除的节点,当cur.left代入参数时,注意这里最精妙的地方是递归函数返回值用cur.left接收
if(cur.val > val){cur.left = insertIntoBST(cur.left,val);
} 
  1. 当要删除当前节点,并且情况为当前节点左右孩子均不为null时,按照二叉搜索树的性质,当前节点的左子树中的所有节点一定比当前节点右子树中最小的节点还要小。所以应该把左子树放到右子树中最左边的叶子节点的左孩子位置,并且用当前节点的右孩子替换当前节点。(这个比较难想到)
TreeNode cur = root.right;
while(cur.left != null){//用循环找到最左边的叶子结点cur = cur.left;
}
cur.left = root.left;//左子树放到右子树中最左边的叶子节点的左孩子位置
return root.right;//用当前节点的右孩子替换当前节点