【leetcode】 450. Delete Node in a BST
Given a root node reference of a BST and a key, delete the node with the given key in the BST. Return the root node reference (possibly updated) of the BST.
Basically, the deletion can be divided into two stages:
- Search for a node to remove.
- If the node is found, delete the node.
Example 1:Input: root = [5,3,6,2,4,null,7],
key = 3Output: [5,4,6,2,null,null,7]
Explanation: Given key to delete is 3. So we find the node with value 3 and delete it. One valid answer is [5,4,6,2,null,null,7], shown in the above BST. Please notice that another valid answer is [5,2,6,null,4,null,7] and it's also accepted.
首先对于BST 来说左子树的节点都比根节点小,右子树的节点都比根节点大,由此可以递归寻找到需要删除的节点。
在删除当前节点的时候需要在该节点的子树中寻找替换节点,同时还要保证BST特性,有点像堆的插入和删除,为了保证依旧保持BST特性,那么替换的节点就是左子树的最大值,或者右子树的最小值,按照这个思路可以把代码写出来。
1、复杂版本 想看最优化的代码请看2号答案,但是下面这个答案确确实实是我第一时间想到的写法,deleteNode 用于检索需要删除的节点,find_right和 find_left 分别用于寻找左子树的最大值,或者右子树的最小值,由于需要替换节点所以还保存了前后两个节点用于删除子树,这个写法很麻烦。而且代码没有完全oc,oc了95%,不知道问题在哪儿。
/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode() : val(0), left(nullptr), right(nullptr) {} * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} * }; */ class Solution { public: TreeNode* deleteNode(TreeNode* root, int key) { //递归 检索由于是bst 二叉树 根据其特性可以快速查找对应的节点 if(root==nullptr) return nullptr; if(root->val<key){ root->right=deleteNode(root->right,key); } else if(root->val>key){ root->left=deleteNode(root->left,key); } else if(root->val==key){ // 替换当前节点 需要寻找右子树的最小节点 或者左子树的最大节点 // 如果右子树为空 就得去找左子树 如果左子树为空就得找右子树 TreeNode* node=nullptr; if(root->right!=nullptr){ node= find_right(root,root->right); //寻找右子树的最小节点 node->left=root->left; node->right=root->right; } else if(root->left!=nullptr){ node= find_left(root,root->left); //寻找左子树的最大节点 node->left=root->left; node->right=root->right; } return node; } return root; } TreeNode* find_right(TreeNode* node,TreeNode* node1){ //存储最后两个节点 TreeNode* root=node; while(node1->left!=nullptr){ node=node1; node1=node1->left; } if(node==root){ node->right=node1->right; } else{ node->left=node1->left; } return node1; } TreeNode* find_left(TreeNode* node,TreeNode* node1){ //存储最后两个节点 TreeNode* root=node; while(node1->right!=nullptr){ node=node1; node1=node1->right; //寻找左子树最大的数 } if(node==root){ node->left=node1->left; } else{ node->right=node1->right; } return node1; } };
2、优化版本,在替换节点的时候可以分三种情况判断以下,(1)无左右子树、(2)只有左子树或者右子树(只要的话删除当前节点即可)、(3)同时有左子树或者右子树,替换后再调用一次deleteNode 即可
/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode() : val(0), left(nullptr), right(nullptr) {} * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} * }; */ class Solution { public: TreeNode* deleteNode(TreeNode* root, int key) { //递归 检索由于是bst 二叉树 根据其特性可以快速查找对应的节点 if(root==nullptr) return nullptr; if(root->val<key){ root->right=deleteNode(root->right,key); } else if(root->val>key){ root->left=deleteNode(root->left,key); } else if(root->val==key){ // 替换当前节点 需要寻找右子树的最小节点 或者左子树的最大节点 // 分三种情况讨论论 // 1 当前节点没有左右子树 if(!root->left && !root->right) return nullptr; // 2 当前节点只有左子树 或者右子树 else if(!root->left || !root->right) return root->left ? root->left:root->right; // 3 当前节点同时有 左子树和右子树 则用左子树的最大节点替换当前节点 TreeNode* node=root->left; while(node->right!=nullptr) node=node->right; // 替换当前节点 root->val=node->val; //但是还要 删除掉这个最右边的节点 下边这个复杂的答案是同时存储两个节点 手动删除 //但是 仔细思考一下 删除这个最右边的节点不就是再调用一遍deleteNode 函数嘛? root->left=deleteNode(root->left,node->val); } return root; } };