首页 > 其他分享 >【代码随想录训练营第42期 Day17打卡 二叉树Part5-LeetCode 654.最大二叉树 617.合并二叉树 700.二叉搜索树中的搜索 98.验证二叉搜索树

【代码随想录训练营第42期 Day17打卡 二叉树Part5-LeetCode 654.最大二叉树 617.合并二叉树 700.二叉搜索树中的搜索 98.验证二叉搜索树

时间:2024-08-02 20:23:43浏览次数:13  
标签:node TreeNode 递归 nums 二叉 搜索 二叉树 节点

目录

一、做题心得

二、题目与题解

题目一:654.最大二叉树

题目链接

题解:递归

题目二:617.合并二叉树

题目链接

题解:递归(前序遍历)

题目三:617.合并二叉树

题目链接

题解:BFS层序遍历

 题目四:98.验证二叉搜索树

题目链接

题解:递归(中序遍历)

三、小结


一、做题心得

今天是代码随想录打卡的第17天,来到了二叉树章节的part5。今天主要运用到的思想依旧是递归,事实证明,递归才是打开二叉树大门的钥匙。个人感觉今天的题总体难度不大,有了前些天的基础,相信都能有自己的思考和想法。不过今天也接触到了一点比较新的东西,就是二叉树搜索树的一些性质,等下会慢慢说到。

好了,直接开始今天的内容。

二、题目与题解

题目一:654.最大二叉树

题目链接

654. 最大二叉树 - 力扣(LeetCode)

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

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

返回 nums 构建的 最大二叉树 

示例 1:

输入:nums = [3,2,1,6,0,5]
输出:[6,3,5,null,2,0,null,null,1]
解释:递归调用如下所示:
- [3,2,1,6,0,5] 中的最大值是 6 ,左边部分是 [3,2,1] ,右边部分是 [0,5] 。
    - [3,2,1] 中的最大值是 3 ,左边部分是 [] ,右边部分是 [2,1] 。
        - 空数组,无子节点。
        - [2,1] 中的最大值是 2 ,左边部分是 [] ,右边部分是 [1] 。
            - 空数组,无子节点。
            - 只有一个元素,所以子节点是一个值为 1 的节点。
    - [0,5] 中的最大值是 5 ,左边部分是 [0] ,右边部分是 [] 。
        - 只有一个元素,所以子节点是一个值为 0 的节点。
        - 空数组,无子节点。

示例 2:

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

提示:

  • 1 <= nums.length <= 1000
  • 0 <= nums[i] <= 1000
  • nums 中的所有整数 互不相同
题解:递归

这个题其实跟昨天打卡的最后一道题:

106. 从中序与后序遍历序列构造二叉树 有些相似,都是要求我们构建二叉树。

构建二叉树一般我们选择前序遍历递归的做法,先构建根节点,再递归构建左右子树。这里题目要求以最大值作为根节点,我们找到最大值在数组中的位置索引index,每次递归的时候,我们都采用分割区间的办法来确定左右子树节点的位置范围。

这里我们自己定义一个函数build(),实现树的建立。(注意必须新构建一个函数,这样才能利于分割区间以及递归的实现--左右子树区间的边界作为函数参数)

代码如下:

class Solution {
public:
    TreeNode* build(vector<int>& nums,int left,int right) {
        //两个特殊情况(递归终止条件)
        if(left > right)    return nullptr;         //当前子数组为空时
        if(left == right)  return new TreeNode(nums[left]);        //当前子数组只有一个元素

        int index = left;       //记录最大值下标,初始化为左边界
        for (int i = left + 1; i <= right; i++) {               //遍历子数组,找到最大值的下标(最大值作为根节点)
            if (nums[i] > nums[index]) {
                index = i;
            }
        }
        TreeNode* node = new TreeNode(nums[index]);         //创建树(根节点的值为nums[index])
        //递归构建左右子树
        node->left = build(nums,left,index - 1);                //左区间
        node->right = build(nums,index + 1,right);              //右区间
        return node;
    }

    TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
       return build(nums,0,nums.size() - 1);
    }
};

题目二:617.合并二叉树

题目链接

617. 合并二叉树 - 力扣(LeetCode)

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

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

返回合并后的二叉树。

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

示例 1:

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

示例 2:

输入:root1 = [1], root2 = [1,2]
输出:[2,2]

提示:

  • 两棵树中的节点数目在范围 [0, 2000] 内
  • -104 <= Node.val <= 104
题解:递归(前序遍历)

这个题个人感觉挺简单的,就是分别把对应节点的值加起来存放在一棵新树里边。这里我们很容易想到递归的方式,按照前序遍历递归添加元素。

class Solution {
public:
    TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
        if (root1 == nullptr)   return root2;
        if (root2 == nullptr)   return root1;
        TreeNode* node = new TreeNode(root1->val + root2->val);
        //递归构建左右子树
        node->left = mergeTrees(root1->left,root2->left);         
        node->right = mergeTrees(root1->right,root2->right);
        return node;
    }
};

题目三:617.合并二叉树

题目链接

700. 二叉搜索树中的搜索 - 力扣(LeetCode)

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

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

示例 1:

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

示例 2:

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

提示:

  • 树中节点数在 [1, 5000] 范围内
  • 1 <= Node.val <= 107
  • root 是二叉搜索树
  • 1 <= val <= 107
题解:BFS层序遍历

这个题也是可以直接套BFS层序遍历模板,没什么难度,题目都只有一棵最大子树满足要求,所以找到目标节点返回对应的子树即可。

这里要注意的就是:TreeNode* node既可以表示节点,也可以表示一棵树(题中直接return node时表示以其为根节点的树)

代码如下:

class Solution {
public:
    TreeNode* searchBST(TreeNode* root, int val) {
        if(root == nullptr)     return nullptr;
        queue<TreeNode*> q;
        q.push(root);
        while (!q.empty()) {
            TreeNode* node = q.front();
            q.pop();
            if (node->val == val) {         //层序遍历找到目标节点
                return node;            
            }
            if(node->left)      q.push(node->left);
            if(node->right)     q.push(node->right);
        }
        return nullptr;
    }
};

 题目四:98.验证二叉搜索树

题目链接

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

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

  • 节点的左

    子树

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

示例 1:

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

示例 2:

输入:root = [5,1,4,null,null,3,6]
输出:false
解释:根节点的值是 5 ,但是右子节点的值是 4 。

提示:

  • 树中节点数目范围在[1, 104] 内
  • -231 <= Node.val <= 231 - 1
题解:递归(中序遍历)

这个题是我感觉今天做的题中最有收获的一道。

可能很多人一开始就想到判断当前节点是否比它的左子结点大以及是否比它的右子节点小,然后在对于该节点的左右节点分别递归,然后,很快就做出来了。但是,结果却出了错。

这里我们得知道二叉搜索树的定义:

1.节点的左子树只包含小于当前节点的数。

2.节点的右子树只包含大于当前节点的数。

3.所有左子树和右子树自身必须也是二叉搜索树。

这下其实仔细一想就知道,刚刚我们只检查了该节点与直接子节点的关系,没有考虑整个树的结构。换句话说,相隔较远的节点它就无法判断与根节点的大小关系。

所以这里我们引入一个新的思路:中序遍历递归。我们知道中序遍历是:左右根的顺序遍历节点,而二叉搜索树刚好就是左根右的大小排序(左<根<右)。然后用pre指针记录当前节点的前一个节点,与当前节点进行比较,判断是否满足逐渐递增即可。

好了,相信这时大家就有思路了,这里直接看代码(附详细注释):

class Solution {
public:
    //这里注意:不能将TreeNode* pre = nullptr;放在isValidBST函数内部,否则每次递归pre都会重新变成nullptr
    TreeNode* pre = nullptr;                //用来记录当前节点的前一个节点
    bool isValidBST(TreeNode* root) {
        if (root == nullptr)    return true;       //注意:空树被认为是有效的BST
        bool left = isValidBST(root->left);             //递归地检查左子树是否是有效的BST(左)
        if (pre != nullptr && pre->val >= root->val)   
            return false;
        pre = root;                 //更新pre的位置:往后移动一个节点(根)
        bool right = isValidBST(root->right);               //递归地检查右子树是否是有效的BST(右)
        return left && right;       //left,right分别存储了递归判断左右子树是否为有效BST的结果,这里要求都满足的时候
    }
};

三、小结

今天的打卡到此也就结束了,递归的应用也进一步加深,希望后边继续加油。最后,我是算法小白,但也希望终有所获。

标签:node,TreeNode,递归,nums,二叉,搜索,二叉树,节点
From: https://blog.csdn.net/2303_79786049/article/details/140878649

相关文章

  • ElasticSearch分布式搜索引擎原理与代码实例讲解
    ElasticSearch分布式搜索引擎原理与代码实例讲解1.背景介绍1.1问题的由来在当今的数字时代,海量的数据被不断产生和存储。如何高效地检索和管理这些庞大的数据集成为了一个关键挑战。传统的关系型数据库虽然在事务处理和数据一致性方面表现出色,但在处理非结构化数据和......
  • 不断自动搜索连接snap7
    我们想通过wifi自动连接PLC。当树莓派启动并自动运行他的程序时。它应该是一个独立的树莓派,所以我们没有键盘或任何东西。我们通过snap7发送数据。这可行,但如果wifi断开连接,我会收到此错误:“ISO:接收TCP期间发生错误:连接超时”有时在程序开始时我们会收到此错误:“Snap7Exc......
  • 数据结构与算法-二分搜索树节点的查找
    ......
  • 无聊写了一个二叉排序
    staticvoidMain(string[]args){varbinarySortTree=newBinarySortTree();vartestSortArray=newint[]{9,8,7,6,5,4,3,2,1,100,99,88};foreach(varitemintestSortArray){......
  • Chrome 桌面版新增 AI 功能,能通过提问搜索你的浏览器历史记录
    谷歌将在Chrome桌面版中推出新的Gemini功能,包括桌面版GoogleLens、购物标签对比功能和自然语言历史搜索。在手机上推出并不断发展的GoogleLens功能,现在终于要在Chrome桌面版上线。它将在地址栏和三点菜单中出现,用户点击后可以选择页面上的一部分,提出更多问题以获取......
  • Day17 二叉树Part5
    目录任务654.最大二叉树思路617.合并二叉树思路700.二叉搜索树中的搜索思路98.验证二叉搜索树思路(错误)思路(正确)心得体会任务654.最大二叉树给定一个不重复的整数数组nums。最大二叉树可以用下面的算法从nums递归地构建:创建一个根节点,其值为nums中的最大值。递归......
  • 代码随想录day17 || 654 最大二叉树,617 合并二叉树,700 二叉搜索树搜索,98 验证二叉搜索
    645最大二叉树funcconstructMaximumBinaryTree(nums[]int)*TreeNode{ //思路,算法思路基本等同于通过中序前序构造二叉树 //1,取最大值作为根节点 //2,切割数组 //3,递归左右子树 iflen(nums)==0{ returnnil } //切割数组取最大值 max,left,right:=......
  • 数据结构:二叉树(链式结构)
    文章目录1.二叉树的链式结构2.二叉树的创建和实现相关功能2.1创建二叉树2.2二叉树的前,中,后序遍历2.2.1前序遍历2.2.2中序遍历2.2.3后序遍历2.3二叉树节点个数2.4二叉树叶子结点个数2.5二叉树第k层结点个数2.6二叉树的深度/高度2.7二叉树查找值为x的结点2.8......
  • bing官方api搜索引擎
    bing官方api搜索引擎1.bingAPI说明微软Bing的搜索API使得开发者能够将Bing的搜索能力集成到自己的应用中,包括对网页、图片、新闻、视频的搜索,以及提供了实体搜索和视觉搜索的功能。这些API支持安全、无广告且能够根据地理位置提供相关信息的搜索结果。BingWebSearch......
  • 解密编程的八大法宝(四)(附二分查找、分治法和图论算法(深度和广度优先搜索、最短路径、最
    算法题中常见的几大解题方法有以下几种::暴力枚举法(BruteForce):这是最基本的解题方法,直接尝试所有可能的组合或排列来找到答案。这种方法适用于问题规模较小的情况,但在大多数情况下效率不高。贪心算法(GreedyAlgorithm):贪心算法在每一步都选择当前看起来最优的解,希望最终能......