代码随想录算法训练营DAY17

代码随想录算法训练营

—day17

文章目录

  • 代码随想录算法训练营
  • 前言
  • 一、654.最大二叉树
    • 递归法
    • 递归法高效版
  • 二、617.合并二叉树
    • 递归法
    • 迭代法
  • 三、 700.二叉搜索树中的搜索
    • 递归法
    • 迭代法
  • 四、 98. 验证二叉搜索树
    • 递归法
  • 总结


前言

今天是算法营的第17天,最近比较忙,题目做完了没来得及写博客,抽空补上了。
今日任务:
● 654.最大二叉树
● 617.合并二叉树
● 700.二叉搜索树中的搜索
● 98.验证二叉搜索树


一、654.最大二叉树

题目链接
文章讲解
视频讲解

最大二叉树的构建过程:
找到数组中的的最大值作为根节点,
最大值左端的剩余元素构建左子树,
最大值右端的剩余元素构建右子树。

递归法

构造二叉树一般是用前序法。

  1. 递归函数的参数和返回值:参数:传入数组 返回值:构造好的二叉树的根节点
  2. 终止条件:剩余数组大小为1,构建剩余的一个节点就退出
  3. 单层递归的逻辑:
    用两个变量,遍历数组,记录最大值和下标。
    最大值作为当前节点值,
    [begin,max)以数组开头和最大值下标为区间,
    递归调用函数,返回的值赋值给当前节点的左节点。
    [max+1,end)以最大值下标后一位和数组结尾为区间,
    递归调用函数,返回的值赋给当前节点的右节点。
/**
 * 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* constructMaximumBinaryTree(vector<int>& nums) {
        TreeNode* node = new TreeNode(0);
        //这里没有判断数组是否为空,是因为题目写了数组大小>=1
        if (nums.size() == 1) {
            node->val = nums[0];
            return node;
        }

        //找到数组中最大的值和对应的下标
        int MaxNum = 0;
        int index = 0;
        for (int i = 0; i < nums.size(); i++) {
            if (nums[i] > MaxNum) {
                MaxNum = nums[i];
                index = i;
            }
        }

        node->val = MaxNum;

        //最大值的左区域,构造左子树
        if (index > 0) { //保证数组大小至少为1
            vector<int> vec(nums.begin(), nums.begin() + index); //左闭右开
            node->left = constructMaximumBinaryTree(vec);
        }
        //最大值的右区域,构造右子树
        if (index < nums.size() - 1) { //保证数组大小至少为1
            vector<int> vec(nums.begin() + index + 1, nums.end()); //左闭右开,+1是因为要跳过node这个节点
            node->right = constructMaximumBinaryTree(vec);
        }

        return node;
    }
};

递归法高效版

其实不需要每次都构建新数组,只需要记录每次获取的最大值左右区间的下标就可以了。跟106.从中序与后序遍历序列构造二叉树一样。
另外这里的终止条件改成遇到空节点,也就是数组大小为0就终止。
所以在单次递归时就不需要再加if了

/**
 * 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 {
private:
TreeNode* traversal(int begin, int end, vector<int>& nums) {
        if (begin >= end) return nullptr; //把空节点移到前面判断,下面递归就不用判断了

        int index = begin;
        for (int i = begin; i < end; i++) {
            if (nums[i] > nums[index]) index = i;
        }

        TreeNode* node = new TreeNode(nums[index]);

        //左闭右开 [begin, index)
        node->left = traversal(begin, index, nums);
        //左闭右开:[index+1, end)
        node->right = traversal(index + 1, end, nums);

        return node;
    }

public:
    TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
        return traversal(0, nums.size(), nums);
    }

    
};

二、617.合并二叉树

题目链接
文章讲解
视频讲解

题目要求从根节点到叶子的路径,所以需要前序遍历,这样才方便让父节点指向孩子节点,找到对应的路径。
这道题目中涉及到回溯,因为需要把路径记录下来,处理完该节点后回退上一个节点再进入另一个节点。

递归法

思路:

  1. 递归函数参数以及返回值:传入两个根节点,返回合并的后的根节点
  2. 终止条件:传入的节点有其中一个为空,则直接返回另一个节点
  3. 单层处理逻辑:将最终结果保存到存入的其中一个二叉树中
  4. 当前节点的值相加,递归调用函数分别获取左节点和右节点。

代码如下:

/**
 * 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* mergeTrees(TreeNode* root1, TreeNode* root2) {
        if (!root1) return root2; //如果两个都为空也没关系,结果也是返回空
        if (!root2) return root1;

        //用root1保存最后结果
        root1->val += root2->val;//中,root1和root2同一个位置的节点值相加
        root1->left = mergeTrees(root1->left, root2->left); //root1和root2同一个位置的左节点递归返回节点
        root1->right = mergeTrees(root1->right, root2->right);//root1和root2同一个位置的右节点递归返回节点
        
        return root1;
    }
};

迭代法

求二叉树对称的时候就是把两个树的节点同时加入队列进行比较,这道题也可以使用把两个节点同时加入队列再取出的方式来模拟层序遍历。
代码如下:

/**
 * 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* mergeTrees(TreeNode* root1, TreeNode* root2) {
        if (!root1) return root2; //当其中一个根节点是空的,返回另外一个根节点
        if (!root2) return root1;

        queue<TreeNode*> que; //用队列来存放需要处理的相邻节点
        que.push(root1);
        que.push(root2);

        while (!que.empty()) {
            TreeNode* node1 = que.front();
            que.pop();
            TreeNode* node2 = que.front();
            que.pop();

            //此处node1和node2肯定不为空
            node1->val += node2->val;

            //将不为空的node1,2的左右节点放入队列
            if (node1->left && node2->left) {
                que.push(node1->left);
                que.push(node2->left);
            }
            if (node1->right && node2->right) {
                que.push(node1->right);
                que.push(node2->right);
            }

            //当node2的左右节点不为空,且node1左右节点为空,将node2相应节点赋值给node1相应节点
            if (!node1->left && node2->left) {
                node1->left = node2->left;
            }

            if (!node1->right && node2->right) {
                node1->right = node2->right;
            }
        }
        return root1;
    }
};

三、 700.二叉搜索树中的搜索

题目链接
文章讲解
视频讲解

二叉搜索树是一个有序树:

  • 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
  • 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
  • 它的左、右子树也分别为二叉搜索树

思路:
根据二叉搜索树的特性,不需要分什么顺序的遍历,因为二叉搜索树本身是有顺序的。

递归法

  1. 递归函数的参数和返回值:传入树的根节点和目标值,返回节点
  2. 终止条件:如果遇到空节点或者当前节点值等于目标值,返回当前节点
  3. 单层递归的逻辑:当前节点值小于目标值,向右递归;大于目标值,向左递归;
/**
 * 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* searchBST(TreeNode* root, int val) {
        //当前节点为空或者当前节点的值等于目标值则返回当前节点
        if (!root || root->val == val) return root;

        TreeNode* result = nullptr;
        //根据二叉搜索树的特性,左节点值 < 当前节点值 < 右节点值
        if (root->val > val) result = searchBST(root->left, val);
        if (root->val < val) result = searchBST(root->right, val);

        return result;
    }
};

迭代法

代码如下:

/**
 * 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* searchBST(TreeNode* root, int val) {
        while (root) {
            if (root->val > val) root = root->left;
            else if (root->val < val) root = root->right;
            else return root;
        }

        return nullptr;
    }
};

四、 98. 验证二叉搜索树

题目链接
文章讲解
视频讲解

思路:
因为二叉搜索树的特性,左中右节点的值是递增的,关键就是验证值是否递增

递归法

  1. 递归函数的参数和返回值:传入树的根节点,返回bool
  2. 终止条件:如果遇到空节点返回true
  3. 单层递归的逻辑:使用中序遍历,保存最大值,如果当前节点的值没有大于保存的最大值,则返回false。否则结合左右递归的结果返回。

代码如下:

/**
 * 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:
    long long maxNum = LONG_MIN; //记录最大值
    bool isValidBST(TreeNode* root) {
        if (root == nullptr) return true; //空节点也算二叉搜索树

        //二叉树的中序遍历的元素是递增,所以用中序判断是否递增可以验证二叉搜索树
        bool left = isValidBST(root->left);

        if (maxNum < root->val) maxNum = root->val;
        else return false; //如果中间节点没有比前面的左节点大,说明不是二叉搜索树

        bool right = isValidBST(root->right);

        return left&right;
    }
};

这里的最大值需要初始化为一个最小值,但是为了防止题目后台数据里有最小值,所以尽量避免用最小值。下面是使用保存节点的方式来保存最大值。

/**
 * 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* pre = nullptr;

    //用节点来代替初始化最小值,避免后台题目数据中有最小值
    bool isValidBST(TreeNode* root) {
        if (root == nullptr) 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;
    }
};

总结

今天主要是学习了:
1.输入是数组的时候,递归的时候可以不需要重新构造新数组,只需要保存对应的下标。
2.需要同时操作两个二叉树,迭代法可以使用队列同时放入两个节点,再取两次出来做处理。
3.二叉搜索树的特性:左<中<右,中序遍历二叉搜索树会得到升序数组。

明天继续加油!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/946042.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Midjourney技术浅析(七):图像风格化

Midjourney 通过风格迁移&#xff08;Style Transfer&#xff09;和图像滤镜&#xff08;Image Filters&#xff09;技术&#xff0c;使用户能够将生成的图像转换为不同的艺术风格或视觉效果。 一、风格迁移&#xff08;Style Transfer&#xff09; 1.1 风格迁移的定义 风格…

Edge安装问题,安装后出现:Could not find Edge installation

解决&#xff1a;需要再安装&#xff08;MicrosoftEdgeWebView2RuntimeInstallerX64&#xff09;。 网址&#xff1a;https://developer.microsoft.com/zh-cn/microsoft-edge/webview2/?formMA13LH#download 如果已经安装了edge&#xff0c;那就再下载中间这个独立程序安装就…

【JAVA高级篇教学】第六篇:Springboot实现WebSocket

在 Spring Boot 中对接 WebSocket 是一个常见的场景&#xff0c;通常用于实现实时通信。以下是一个完整的 WebSocket 集成步骤&#xff0c;包括服务端和客户端的实现。本期做个简单的测试用例。 目录 一、WebSocket 简介 1. 什么是 WebSocket&#xff1f; 2. WebSocket 的特…

Painter-Mortadela靶场

信息收集 枚举端口 nmap 192.168.109.132 -sS -sV -min-rate 5000 -Pn -p- -p- &#xff1a;扫描所有端口。 (65535)-sS&#xff1a;执行TCP SYN 扫描以快速扫描哪些端口打开。-sC&#xff1a;使用基本识别脚本执行扫描-sV&#xff1a;执行服务扫描–min-rate 5000&#xff1…

攻防世界pwn刷题

get_shell 这题直接给shell了 exp from pwn import* p remote(61.147.171.105,59682) p.sendline(cat flag) p.interactive() cyberpeace{8cd678c722f48327a69b2661ae8956c8} hello_pwn checksec一下 ok&#xff0c;64位的 {alarm(0x3Cu);setbuf(stdout, 0LL);puts("…

1、pycharm、python下载与安装

1、去官网下载pycharm 官网&#xff1a;https://www.jetbrains.com/pycharm/download/?sectionwindows 2、在等待期间&#xff0c;去下载python 进入官网地址&#xff1a;https://www.python.org/downloads/windows/ 3、安装pycharm 桌面会出现快捷方式 4、安装python…

epoll的ET和LT模式

LevelTriggered&#xff1a;简称LT&#xff0c;当FD有数据可读时&#xff0c;会重复通知多次&#xff0c;直至数据处理完成。是epoll的默认模式EdgeTriggered&#xff1a;简称ET&#xff0c;当FD有数据可读时&#xff0c;只通知一次&#xff0c;不管数据是否处理完成 Level是指…

CSS利用浮动实现文字环绕右下角,展开/收起效果

期望实现 文字最多展示 N 行&#xff0c;超出部分截断&#xff0c;并在右下角显示 “…” “更多”&#xff1b; 点击更多&#xff0c;文字展开全部内容&#xff0c;右下角显示“收起”。效果如下&#xff1a; 思路 尽量使用CSS控制样式&#xff0c;减少JS代码复杂度。 利…

单元测试入门和mockup

Java 新手入门&#xff1a;Java单元测试利器&#xff0c;Mock详解_java mock-CSDN博客 这个是典型的before when assert三段式&#xff0c;学一下单测思路 这个没有动态代理&#xff0c;所以是直接class(对比下面) Jmockit使用笔记_增加代码覆盖率_覆盖try catch_使用new Mock…

开发小工具:ping地址

开发小工具&#xff1a;ping地址 import socketdef tcp_port_scan(ip,port):#创建套接字socksocket.socket(socket.AF_INET,socket.SOCK_STREAM)#设置超时sock.settimeout(0.2)try:#发请求result sock.connect_ex((ip,port))if result 0:print(f{ip}--{port}接口连接成功)res…

双汇火腿肠,请勿随意喂猫

在许多家庭中&#xff0c;猫咪作为可爱的宠物成员&#xff0c;备受宠爱。当我们享受着双汇火腿肠的便捷与美味时&#xff0c;或许会有人想到与猫咪分享&#xff0c;但这种看似温馨的举动实则隐藏着诸多问题&#xff0c;双汇火腿肠并不适合喂猫。 从营养成分来看&#xff0c;双…

Unity Excel转Json编辑器工具

功能说明&#xff1a;根据 .xlsx 文件生成对应的 JSON 文件&#xff0c;并自动创建脚本 注意事项 Excel 读取依赖 本功能依赖 EPPlus 库&#xff0c;只能读取 .xlsx 文件。请确保将该脚本放置在 Assets 目录下的 Editor 文件夹中。同时&#xff0c;在 Editor 下再创建一个 Exc…

深信服云桌面系统的终端安全准入设置

深信服的云桌面系统在默认状态下没有终端的安全准入设置&#xff0c;这也意味着同样的虚拟机&#xff0c;使用云桌面终端或者桌面套件都可以登录&#xff0c;但这也给系统带来了一些安全隐患&#xff0c;所以&#xff0c;一般情况下需要设置终端的安全准入策略&#xff0c;防止…

基于SpringBoot的实验室信息管理系统【源码+文档+部署讲解】

系统介绍 视频演示 基于SpringBootVue实现的实验室信息管理系统采用前后端分离的架构方式&#xff0c;系统分为管理员、老师、用户三种角色&#xff0c;实现了用户管理、设备管理、实验室查询、公告、课程、实验室耗材管理、我的等功能 技术选型 开发工具&#xff1a;idea2…

Windows 10 自带功能实现大屏、小屏无线扩展

一、添加可选功能 在作为无线投屏对象的「第二屏」设备上&#xff0c;打开 Windows 10 设置并定位至「应用 > 应用和功能」界面&#xff0c;然后点击右侧界面中的「可选功能」选项。 点击可选功能界面顶部的「添加功能」按钮&#xff0c;搜索「无线显示器」模块并选择添加。…

大电流和大电压采样电路

大电压采样电路&#xff1a; 需要串联多个电阻进行分压&#xff0c;从而一级一级降低电压&#xff0c;防止电阻损坏或者短路直接打穿MCU。 为什么需要加电压跟随器&#xff1a;进行阻抗的隔离&#xff0c;防止MCU的IO阻抗对分压产生影响&#xff1a; 大电流检测电路&#xff…

torch.nn.functional的用法

文章目录 介绍激活函数示例 损失函数示例 卷积操作示例 池化示例 归一化操作示例 Dropout示例 torch.nn.functional 与 torch.nn 的区别 介绍 torch.nn.functional 是 PyTorch 中的一个模块&#xff0c;提供了许多函数式的神经网络操作&#xff0c;包括激活函数、损失函数、卷…

生物信息学软件开发综述学习

目录 ①编程语言和开源工具和库 ②轻量级 R 包开发 ③大规模组学软件开发 ④示例 1.轻量级 R 包开发示例及数据 2.大规模组学软件开发 文献&#xff1a;Bioinformatics software development: Principles and future directions ①编程语言和开源工具和库 在生物信息学…

【复刻】数字化转型是否赋能企业新质生产力发展?(2015-2023年)

参照赵国庆&#xff08;2024&#xff09;的做法&#xff0c;对来自产业经济评论《企业数字化转型是否赋能企业新质生产力发展——基于中国上市企业的微观证据》一文中的基准回归部分进行复刻基于2015-2023年中国A股上市公司数据&#xff0c;实证分析企业数字化转型对新质生产力…

在线免费批量生成 Word 文档工具

为了方便的批量生成 Word 文档&#xff0c;写了个在线 Word 文档批量生成工具&#xff0c;可以根据 Excel 数据和 Word 模板批量生成大量个性化的 Word 文档。适用于需要批量生成格式统一但内容不同的文档场景。比如&#xff1a; 批量生成证书、奖状批量生成合同、协议批量生成…