当前位置: 首页 > news >正文

算法day20|669. 修剪二叉搜索树、将有序数组转换为二叉搜索树、538.把二叉搜索树转换为累加树

算法day20|669. 修剪二叉搜索树、将有序数组转换为二叉搜索树、538.把二叉搜索树转换为累加树

  • 669. 修剪二叉搜索树
  • 08.将有序数组转换为二叉搜索树
  • 538.把二叉搜索树转换为累加树

669. 修剪二叉搜索树

class Solution {
public:TreeNode* traversal(TreeNode* root, int low, int high){if(root==nullptr)return nullptr;if(root->val<low){TreeNode*right=traversal(root->right,low,high);return right;}if(root->val>high){TreeNode*left=traversal(root->left,low,high);return left;}root->left=traversal(root->left,low,high);root->right=traversal(root->right,low,high);return root;}TreeNode* trimBST(TreeNode* root, int low, int high) {return traversal(root,low,high);}
};

重点讲单层递归逻辑:首先,题目本质要求、返回值和逻辑三者是紧密结合的。题目要求返回最后树的根节点,那么我们的返回值肯定要选节点类型。再选择了返回值之后,我们移除节点的逻辑是什么样的呢?答:如果这个结点真的需要删除,那我们就用它可能成立的子树去替代,也就是说,这个结点被它的子树覆盖了。如果不是,该节点还是该节点。

本质就是检查是否“德不配位”:如果配位,你还在这个位置上;如果不配位,你就要下台,让你下面的子孙来顶替。当然,这子孙也要经过考验,所以实际是被考验后的子孙替代。

由于对当前结点的处理不需要借助孩子的信息,所以使用先序。当父亲确定好之后才能正常去遍历。

二叉树的修剪与删除的区别点在哪里?答:

  • 首先删除的核心操作在终止条件下进行,当遇到要删除的结点时,整个遍历过程其实已经结束了;而移除是对当前结点的处理。核心不同点终止条件里面是不能使用递归的,因为到这里递归一斤停止了;而对当前结点的处理是可以使用递归的。这也是判断是否区分两者的重要依据,所以使用和判断相辅相成。
  • 其次,

两者共同点:

  • 都是用root->left或者root->right来接收递归返回值,因为在每一次递归,结点都要经过审判,如果满足某种条件它就要被剔除或者替代,所以这是直接面向结点的、决定结点命运和生死的操作,所以直接用结点本身来接收。
  • 每一次返回的值是对当前结点的替代节点。可以是Null、可以是其他结点,也可以是它本身。这个和用root->left或者root->right来接收递归返回值是息息相关的,所以两者是统一考虑的。

08.将有序数组转换为二叉搜索树

class Solution {
public:TreeNode* traversal(vector<int>& nums,int left,int right){if(left>right)return nullptr;int mid=(left+right)/2;TreeNode* root=new TreeNode(nums[mid]);root->left=traversal(nums,left,mid-1);root->right=traversal(nums,mid+1,right);return root;}TreeNode* sortedArrayToBST(vector<int>& nums) {return traversal(nums,0,nums.size()-1);}
};

建立树肯定是从根节点往下建立的,所以关键是找到该插入数组中的哪一项。

我们在原数组中用两个指针,表示区间的边界(左闭右闭),通过计算,mid指针恰好指向要插入的元素。采用先序遍历,在当前结点处理完之后,左孩子用左区间,右孩子用右区间。

易错:

  • 终止条件,这里的终止条件不是数组的size为0,因为我们并没有对数组做任何的改变,我们只是用了两个指针来限定区间,所以终止条件肯定与两指针的位置有关。
  • 遵循循环不变量的原则,自始至终都遵循同一个区间标准,这里就是左闭右闭。

538.把二叉搜索树转换为累加树

class Solution {
public:int pre=0;void traversal(TreeNode*root){if(root==nullptr)return;traversal(root->right);root->val+=pre;pre=root->val;traversal(root->left);return;}TreeNode* convertBST(TreeNode* root) {if(root==nullptr)return nullptr;traversal(root);return root;}
};

做这题需要巧劲,我一开始是从前往后加的,时间复杂度高不说,中间过程还非常繁琐,导致出错。而正确的思路是从后往前加,用pre指针记录之前的值,从而实现了边遍历边加。所以有时候按常规思维做题很费劲的时候,不妨停下来,换一种思路再想一遍。


http://www.mrgr.cn/news/19036.html

相关文章:

  • MySQL 锁机制详解
  • 跟我一起学FPGA (二) 语法讲解
  • 八股训练营感想
  • 多表查询_关联查询
  • 【win11】win11取消开机密码
  • 嵌入式Linux:常见信号的默认行为
  • 在vue项目中,有两个tab页,在其中一个页面调用另一个页面的方法
  • AUTOSAR_EXP_ARAComAPI的3章节笔记
  • 如何从 Bak 文件中恢复 SQL数据库?(3种方法)
  • 学习记录——day42 多态
  • 浅谈 cookie 和 session
  • CMake构建学习笔记14-依赖库管理工具
  • 苍穹外卖项目前端DAY02
  • 老师怎样用微信发布月考成绩?
  • [CISCN2019 华东南赛区]Web111
  • 数分基础(06)商业分析四种类型简介
  • chrome插件开发资料
  • AI制作情侣头像副业项目,每天只需2小时,收入是我工资的三倍(附教程)
  • 一文带你深度了解FreeRTOS——计数型信号量
  • 【系统架构设计师-2021年】综合知识-答案及详解