当前位置:   article > 正文

代码随想录算法训练营day 22|第六章 二叉树part08

代码随想录算法训练营day 22|第六章 二叉树part08

235. 二叉搜索树的最近公共祖先 

相对于 二叉树的最近公共祖先 本题就简单一些了,因为 可以利用二叉搜索树的特性。 

题目链接/文章讲解:代码随想录

视频讲解:二叉搜索树找祖先就有点不一样了!| 235. 二叉搜索树的最近公共祖先_哔哩哔哩_bilibili

这道题明晃晃就要是要利用二叉搜索树的节点大小的特点,如果当前节点的值比这两个的都要大,那就往左边找(单独左子树递归即可),如果当前的值比这两个的值都要小那就往右边找(单独右子树递归即可),如果恰好处于中间的一个值,那就证明当前节点就是最近公共祖先,然后返回给上个节点的递归即可(这么找上个节点必然是这个节点的父母节点,所以必然比这两个数都大或小),再直接返回找到的结果即可——

  1. TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
  2. // if(root==NULL||root==p||root==q) return root;
  3. if(root->val<min(p->val,q->val)){
  4. return lowestCommonAncestor(root->right,p,q);
  5. }
  6. if(root->val>max(p->val,q->val)){
  7. return lowestCommonAncestor(root->left,p,q);
  8. }
  9. return root;
  10. }

其实,一旦遇到二叉搜索树,迭代法就会很简单,因为二叉搜索树的题它一般都是要利用它的节点大小特点,所以搜索的路径一般都是固定的。这题的思路和递归的一样——

  1. TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
  2. while(root){
  3. if(root->val>max(p->val,q->val)) root=root->left;
  4. else if(root->val<min(p->val,q->val)) root=root->right;
  5. else return root;
  6. }
  7. return NULL;
  8. }

701.二叉搜索树中的插入操作  

本题比想象中的简单,大家可以先自己想一想应该怎么做,然后看视频讲解,就发现 本题为什么比较简单了。

题目链接/文章讲解:代码随想录

视频讲解:原来这么简单? | LeetCode:701.二叉搜索树中的插入操作_哔哩哔哩_bilibili

这道题首先说可以不调整节点,就说明可以将所有加入的节点都放在叶子节点处,不调整整棵树,这样就会简单很多。

使用递归的方法,首先要明确递归何时结束,也就是当当前节点为空的时候,就意味着要返回你的新节点了(已经到达了当前树的叶子节点),如果当前不为空,就要判断当前节点的值大于还是小于加入的值,然后直接将递归调用的返回节点作为当前节点的左子树或右子树,然后最后返回整棵树,作为上一层的左子树或右子树——

  1. TreeNode* insertIntoBST(TreeNode* root, int val) {
  2. if(root==NULL) return new TreeNode(val);
  3. if(root->val>val) root->left=insertIntoBST(root->left,val);
  4. if(root->val<val) root->right=insertIntoBST(root->right,val);
  5. return root;
  6. }

迭代法是很简单的,就是找到合适的叶子节点处,然后给这个叶子节点加一个子节点即可——

  1. TreeNode* insertIntoBST(TreeNode* root, int val) {
  2. if(root==NULL) return new TreeNode(val);
  3. TreeNode* cur=root;
  4. TreeNode* pre=NULL;
  5. while(cur){
  6. pre=cur;
  7. if(cur->val>val) cur=cur->left;
  8. else cur=cur->right;
  9. }
  10. cur=new TreeNode(val);
  11. if(pre->val>val) pre->left=cur;
  12. else pre->right=cur;
  13. return root;
  14. }

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

相对于 插入操作,本题就有难度了,涉及到改树的结构 

题目链接/文章讲解:代码随想录

视频讲解:调整二叉树的结构最难!| LeetCode:450.删除二叉搜索树中的节点_哔哩哔哩_bilibili

这道题其实主要是要搞懂怎么删除节点,要删除的节点分成三种情况:

  1. 左孩子、右孩子送都为NULL的,这样直接delete节点,返回NULL即可,这种最简单。
  2. 左孩子和右孩子有且仅有一个为空,这样直接返回不为空的那个节点即可,记得要delete节点。
  3. 左孩子和右孩子均不为空,这种是最难考虑的,我一开始是想直接找左孩子的最右子节点来作为替换当前节点,但这样要考虑的情况实在太多,而文章则是将左孩子一股脑全给了右孩子的最左节点,这样又简单又能符合要求。
  1. TreeNode* aided(TreeNode* node){
  2. if(node->left==NULL&&node->right==NULL) {
  3. delete(node);
  4. return NULL;
  5. }
  6. TreeNode* tmp=node;
  7. if(node->left&&node->right==NULL){
  8. tmp=tmp->left;
  9. delete(node);
  10. return tmp;
  11. }
  12. if(node->right&&node->left==NULL){
  13. tmp=tmp->right;
  14. delete(node);
  15. return tmp;
  16. }
  17. tmp=tmp->right;
  18. while(tmp->left){
  19. tmp=tmp->left;
  20. }
  21. tmp->left=node->left;
  22. tmp=node->right;
  23. delete(node);
  24. return tmp;
  25. }
  26. TreeNode* deleteNode(TreeNode* root, int key) {
  27. if(!root) return NULL;
  28. if(root->val==key){
  29. return aided(root);
  30. }else if(root->val>key) root->left=deleteNode(root->left,key);
  31. else root->right=deleteNode(root->right,key);
  32. return root;
  33. }

文章还给出了删除普通二叉树的方法,就是当要删除的节点本身没有右孩子的时候,直接返回左孩子,如果有右孩子,那就将右孩子的最左边的孩子的值和当前节点的值交换一下,一直交换到目标节点的右孩子为空为止,这样再直接返回目标节点的左孩子。这样做本质上是没有对要删除的节点进行彻底的空间释放——

  1. TreeNode* deleteNode(TreeNode* root, int key) {
  2. if (root == nullptr) return root;
  3. if (root->val == key) {
  4. if (root->right == nullptr) { // 这里第二次操作目标值:最终删除的作用
  5. return root->left;
  6. }
  7. TreeNode *cur = root->right;
  8. while (cur->left) {
  9. cur = cur->left;
  10. }
  11. swap(root->val, cur->val); // 这里第一次操作目标值:交换目标值其右子树最左面节点。
  12. }
  13. root->left = deleteNode(root->left, key);
  14. root->right = deleteNode(root->right, key);
  15. return root;
  16. }

迭代的做法。首先要找到要删除的目标节点,然后再把删除节点之后的子树移接到它的父母节点,如果没有父母节点,就直接返回删除后的子树。删除节点主要考虑到三种情况:

  1. 当前节点为空,也就是没有找到目标节点。
  2. 当前节点的右子树为空,那就直接返回左子树。
  3. 当前节点的右子树不为空,那就将左子树移动到右子树的最左子节点上,其实本质上包含了右子树为空左子树不为空的情况。
  1. class Solution {
  2. private:
  3. // 将目标节点(删除节点)的左子树放到 目标节点的右子树的最左面节点的左孩子位置上
  4. // 并返回目标节点右孩子为新的根节点
  5. // 是动画里模拟的过程
  6. TreeNode* deleteOneNode(TreeNode* target) {
  7. if (target == nullptr) return target;
  8. if (target->right == nullptr) return target->left;
  9. TreeNode* cur = target->right;
  10. while (cur->left) {
  11. cur = cur->left;
  12. }
  13. cur->left = target->left;
  14. return target->right;
  15. }
  16. public:
  17. TreeNode* deleteNode(TreeNode* root, int key) {
  18. if (root == nullptr) return root;
  19. TreeNode* cur = root;
  20. TreeNode* pre = nullptr; // 记录cur的父节点,用来删除cur
  21. while (cur) {
  22. if (cur->val == key) break;
  23. pre = cur;
  24. if (cur->val > key) cur = cur->left;
  25. else cur = cur->right;
  26. }
  27. if (pre == nullptr) { // 如果搜索树只有头结点
  28. return deleteOneNode(cur);
  29. }
  30. // pre 要知道是删左孩子还是右孩子
  31. if (pre->left && pre->left->val == key) {
  32. pre->left = deleteOneNode(cur);
  33. }
  34. if (pre->right && pre->right->val == key) {
  35. pre->right = deleteOneNode(cur);
  36. }
  37. return root;
  38. }
  39. };

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/128120
推荐阅读
相关标签
  

闽ICP备14008679号