day20 | 654.最大二叉树、617.合并二叉树、700.二叉搜索树中的搜索、98.验证二叉搜索树

news/2024/11/17 20:25:54/

目录:

解题及思路学习

654.最大二叉树

654. 最大二叉树

给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建:

  1. 创建一个根节点,其值为 nums 中的最大值。
  2. 递归地在最大值 左边 的 子数组前缀上 构建左子树。
  3. 递归地在最大值 右边 的 子数组后缀上 构建右子树。

返回 nums 构建的 最大二叉树 。

示例 1:

!https://assets.leetcode.com/uploads/2020/12/24/tree1.jpg

输入:nums = [3,2,1,6,0,5]
输出:[6,3,5,null,2,0,null,null,1]

思考:递归方法,每次传入区间。递归里面找到最大值的索引。

class Solution {
private:// 在左闭右开区间[left, right),构造二叉树TreeNode* traversal(vector<int>& nums, int left, int right) {if (left >= right) return nullptr;// 分割点下标:maxValueIndexint maxValueIndex = left;for (int i = left + 1; i < right; ++i) {if (nums[i] > nums[maxValueIndex]) maxValueIndex = i;}TreeNode* root = new TreeNode(nums[maxValueIndex]);// 左闭右开:[left, maxValueIndex)root->left = traversal(nums, left, maxValueIndex);// 左闭右开:[maxValueIndex + 1, right)root->right = traversal(nums, maxValueIndex + 1, right);return root;}
public:TreeNode* constructMaximumBinaryTree(vector<int>& nums) {return traversal(nums, 0, nums.size());}
};

注意类似用数组构造二叉树的题目,每次分隔尽量不要定义新的数组,而是通过下标索引直接在原数组上操作,这样可以节约时间和空间上的开销。

一般情况来说:如果让空节点(空指针)进入递归,就不加if,如果不让空节点进入递归,就加if限制一下, 终止条件也会相应的调整

617.合并二叉树

617. 合并二叉树

给你两棵二叉树: root1 和 root2 。

想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。

返回合并后的二叉树。

注意: 合并过程必须从两个树的根节点开始。

示例 1:

!https://assets.leetcode.com/uploads/2021/02/05/merge.jpg

输入:root1 = [1,3,2,5], root2 = [2,1,3,null,4,null,7]
输出:[3,4,5,5,4,null,7]

思考:可以直接在root1上进行修改。

class Solution {
public:TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {if (root1 == NULL) return root2;if (root2 == NULL) return root1;root1->val += root2->val;root1->left = mergeTrees(root1->left, root2->left);root1->right = mergeTrees(root1->right, root2->right);return root1;}
};

迭代法

使用迭代法同时处理两棵树就是要把这两棵树的节点同时加入队列进行比较。

class Solution {
public:TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {if (t1 == NULL) return t2;if (t2 == NULL) return t1;queue<TreeNode*> que;que.push(t1);que.push(t2);while(!que.empty()) {TreeNode* node1 = que.front(); que.pop();TreeNode* node2 = que.front(); que.pop();// 此时两个节点一定不为空,val相加node1->val += node2->val;// 如果两棵树左节点都不为空,加入队列if (node1->left != NULL && node2->left != NULL) {que.push(node1->left);que.push(node2->left);}// 如果两棵树右节点都不为空,加入队列if (node1->right != NULL && node2->right != NULL) {que.push(node1->right);que.push(node2->right);}// 当t1的左节点 为空 t2左节点不为空,就赋值过去if (node1->left == NULL && node2->left != NULL) {node1->left = node2->left;}// 当t1的右节点 为空 t2右节点不为空,就赋值过去if (node1->right == NULL && node2->right != NULL) {node1->right = node2->right;}}return t1;}
};

700.二叉搜索树中的搜索

700. 二叉搜索树中的搜索

给定二叉搜索树(BST)的根节点 root 和一个整数值 val

你需要在 BST 中找到节点值等于 val 的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 null 。

示例 1:

!https://assets.leetcode.com/uploads/2021/01/12/tree1.jpg

输入:root = [4,2,7,1,3], val = 2
输出:[2,1,3]

思考:比较当前root的值和val,如果val大,则从右子树查找。如果val小,则从左子树查找。

class Solution {
public:TreeNode* searchBST(TreeNode* root, int val) {if (root == NULL || root->val == val) return root;TreeNode* result = NULL;if (root->val < val) {result = searchBST(root->right, val);}if (root->val > val) {result = searchBST(root->left, val);}return result;}
};另一种写法:
class Solution {
public:TreeNode* searchBST(TreeNode* root, int val) {if (root == NULL || root->val == val) return root;if (root->val < val) {return searchBST(root->right, val);}if (root->val > val) {return searchBST(root->left, val);}return nullptr;}
};

迭代法:

class Solution {
public:TreeNode* searchBST(TreeNode* root, int val) {while(root != NULL) {if (root->val > val) root = root->left;else if (root->val < val) root = root->right;else return root;}return NULL;}
};

98.验证二叉搜索树

98. 验证二叉搜索树

给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。

有效 二叉搜索树定义如下:

  • 节点的左子树只包含 小于 当前节点的数。
  • 节点的右子树只包含 大于 当前节点的数。
  • 所有左子树和右子树自身必须也是二叉搜索树。

示例 1:

!https://assets.leetcode.com/uploads/2020/12/01/tree1.jpg

输入:root = [2,1,3]
输出:true

思考:递归方法,当有false时,全返回false。

下面是一种错误写法,因为只用到了中间节点的左右值来进行判断。只注意到了局部而不是整体。

class Solution {
public:bool isValidBST(TreeNode* root) {if (root == NULL) return true;if (root->left && root->val <= root->left->val) return false;if (root->right && root->val >= root->right->val) return false;bool left = isValidBST(root->left);bool right = isValidBST(root->right);return (left && right);}
};改正之后的写法,用一个值来一直记录
class Solution {
public:long long maxVal = LONG_MIN;bool isValidBST(TreeNode* root) {if (root == NULL) return true;bool left = isValidBST(root->left);if (maxVal < root->val) maxVal = root->val;else return false;bool right = isValidBST(root->right);return left && right;}
};

可以用一个指针来记录前一个的值,然后中序遍历,保证一直是递增的,则为搜索二叉树。

class Solution {
public:TreeNode* pre = NULL;bool isValidBST(TreeNode* root) {if(root == NULL) return true;bool left = isValidBST(root->left);if (pre && pre->val >= root->val) {return false;}pre = root;bool right = isValidBST(root->right);return (left && right);}
};

迭代法:

迭代法的中序遍历稍加改动。

class Solution {
public:bool isValidBST(TreeNode* root) {stack<TreeNode*> st;TreeNode* cur = root;TreeNode* pre = NULL; // 记录前一个节点while (cur != NULL || !st.empty()) {if (cur != NULL) {st.push(cur);cur = cur->left;                // 左} else {cur = st.top();                 // 中st.pop();if (pre != NULL && cur->val <= pre->val)return false;pre = cur; //保存前一个访问的结点cur = cur->right;               // 右}}return true;}
};

复盘总结

个人反思

1、使用迭代法同时处理两棵树就是要把这两棵树的节点同时加入队列进行比较。

2、二叉搜索树要尽量用中序遍历,利用二叉搜索树的特性。用一个指针记录前一个节点,是个很好的思路。

3、注意类似用数组构造二叉树的题目,每次分隔尽量不要定义新的数组,而是通过下标索引直接在原数组上操作,这样可以节约时间和空间上的开销。

4、一般情况来说:如果让空节点(空指针)进入递归,就不加if,如果不让空节点进入递归,就加if限制一下, 终止条件也会相应的调整


http://www.ppmy.cn/news/1043654.html

相关文章

批量将excel中第5列中内容将人名和电话号码进行分列

使用Python可以使用openpyxl库来实现批量将Excel中第5列的内容分列为人名和电话号码的操作。下面是示例代码&#xff1a; import openpyxl def split_names_and_phone_numbers(file_path, sheet_name): # 加载Excel文件 workbook openpyxl.load_workbook(file_path) …

前端对文件转换处理的一些常用方法

文章目录 0&#xff0c;前言1&#xff0c;将图片的url网络链接(http://) 转为base64格式2&#xff0c;将base64的图片数据转换为file文件3&#xff0c;将以base64的图片数据转换为Blob4&#xff0c;将file文件转化为base645&#xff0c;将file文件转换为Blob6&#xff0c;获取文…

在海外如何进行应用商店的关键词优化

分析市场&#xff0c;了解我们的应用类别&#xff0c;将我们的应用与竞争对手的优点和缺点进行比较&#xff0c;找到市场上的空白或所谓未满足的需求&#xff0c;并思考如何填补。 1、应用商店关键词优化。 关键词优化的目的是找到最相关的关键词 &#xff0c;并测试应用元数据…

Focus-DETR利用双重注意力机制重建编码器,打造最强目标检测模型

前期的文章我们介绍了DETR模型,我们知道DETR模型首先使用CNN卷积神经网络搜集图片的核心特征点,然后把这些特征点整合起来,通过embedding方法,把特征图片转换到特征向量空间。然后根据标准Transformer模型的编码器与解码器进行注意力机制的计算,最后把计算后的数据进行图片…

稚晖君人形机器人问世:大模型加持,会自己换胳膊,要上生产线造车

从零开始,不到半年就造出人形机器人,还自带软硬件体系。 大模型技术的新一波浪潮:具身智能,已经有了重要进展。 刚刚,稚晖君的创业公司「智元机器人」开了自己的第一场发布会。 以「天才少年」身份加入华为的稚晖君(彭志辉)于去年底宣布离职创业,人们都在关注他在机器…

寻路算法(Java 实例代码源码包下载)

目录 寻路算法 Java 实例代码 src/runoob/graph/Path.java 文件代码&#xff1a; 寻路算法 图的寻路算法也可以通过深度优先遍历 dfs 实现&#xff0c;寻找图 graph 从起始 s 点到其他点的路径&#xff0c;在上一小节的实现类中添加全局变量 from数组记录路径&#xff0c;fr…

SpringBoot + Vue 微人事(十)

职位管理前后端接口对接 先把table中的数据展示出来&#xff0c;table里面的数据实际上是positions里面的数据&#xff0c;就是要给positions:[] 赋上值 可以在methods中定义一个initPosition方法 methods:{//定义一个初始化positions的方法initPositions(){//发送一个get请求…

shell脚本文本三剑客sed

shell脚本文本三剑客sed 一.Sed编辑器1.1sed概述1.2sed工作流程1.3sed基本法1.4sed常用选项1.5sed命令的常用操作 二.sed命令使用2.1打印内容2.2删除内容示例5&#xff1a;先备份内容在删除2.3插入内容2.4取反2.5搜索替代2.6分组调用 一.Sed编辑器 1.1sed概述 sed编辑器是一种…