代码随想录算法训练营DAY17

news2025/1/5 8:10:36

代码随想录算法训练营

—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.二叉搜索树的特性:左<中<右,中序遍历二叉搜索树会得到升序数组。

明天继续加油!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL数据库笔记——多版本并发控制MVCC

大家好&#xff0c;这里是Good Note&#xff0c;关注 公主号&#xff1a;Goodnote&#xff0c;本文详细介绍MySQL的并发控制&#xff1a;多版本并发控制MVCC。 文章目录 背景介绍数据库并发控制——锁机制悲观锁和乐观锁悲观锁乐观锁 数据库并发控制——MVCC 的引入MVCC 和锁机…

css3实现文字下滑波浪线

上效果 上菜 text-decoration 属性作用&#xff1a;用于设置或检索文本的装饰线&#xff0c;如下划线、上划线、删除线等 text-decoration: line || color || style; 参数&#xff1a; line: 指定装饰线类型&#xff0c;如 underline&#xff08;下划线&#xff09;、overline&…

Springboot 3项目整合Knife4j接口文档(接口分组详细教程)

文章目录 前言一、Spring Boot 3.0整合Knife4j二、OpenApi 3注解的使用规范三、使用步骤 1.Spring Boot 3.0项目中使用knife4j2.在application.yml中添加knife4j相关配置3.设置WebMvc相关配置&#xff08;解决封装统一异常处理后doc.html无法打开的问题&#xff09;4.创建Knif…

2024年中国新能源汽车用车发展怎么样 PaperGPT(一)

概述 在国家政策的强力扶持下&#xff0c;2024年中国新能源汽车市场迎来了新的发展机遇。本文将基于《中国新能源汽车用车报告&#xff08;2024年&#xff09;》的数据&#xff0c;对新能源汽车的市场发展和用车趋势概述。 新能源汽车市场发展 政策推动&#xff1a;国家和地…

华三交换机如何进行堆叠?

准备&#xff1a;两台交换机堆叠 1、进行连线 2、交换机都选取 FortyGigE1/0/53 和 FortyGigE1/0/54 做 堆叠口 配置&#xff1a;进行交换机配置 X_T1_Core_1&#xff1a; [X_T1_Core_1]irf domain 0 //同一拓扑内如果有其它堆叠组&#xff0c;domain不能重复 [X_T1_Core_1]…

活动预告 | Microsoft 安全在线技术公开课:通过扩展检测和响应抵御威胁

课程介绍 通过 Microsoft Learn 免费参加 Microsoft 安全在线技术公开课&#xff0c;掌握创造新机遇所需的技能&#xff0c;加快对 Microsoft Cloud 技术的了解。参加我们举办的“通过扩展检测和响应抵御威胁”技术公开课活动&#xff0c;了解如何更好地在 Microsoft 365 Defen…

Sonic:开源Go语言开发的高性能博客平台

Sonic&#xff1a;一个用Go语言开发的高性能博客平台 简介 Sonic&#xff0c;一个以其速度如声速般快速而命名的博客平台&#xff0c;是一个用Go语言开发的高性能博客系统。正如其名字所暗示的&#xff0c;Sonic旨在提供一个简单而强大的博客解决方案。这个项目受到了Halo项目…

大模型WebUI:Gradio全解系列8——Additional Features:补充特性(上)

大模型WebUI&#xff1a;Gradio全解系列8——Additional Features&#xff1a;补充特性&#xff08;上&#xff09; 前言本篇摘要8. Additional Features&#xff1a;补充特性8.1 队列8.1.1 使用方法8.1.2 配置队列演示 8.2 输入输出流8.2.1 输出流1. 生成器yield2. 流媒体 8.2…

音视频入门基础:MPEG2-PS专题(4)——FFmpeg源码中,判断某文件是否为PS文件的实现

一、引言 通过FFmpeg命令&#xff1a; ./ffmpeg -i XXX.ps 可以判断出某个文件是否为PS文件&#xff1a; 所以FFmpeg是怎样判断出某个文件是否为PS文件呢&#xff1f;它内部其实是通过mpegps_probe函数来判断的。从《FFmpeg源码&#xff1a;av_probe_input_format3函数和AVI…

【Leetcode】3280. 将日期转换为二进制表示

文章目录 题目思路代码复杂度分析时间复杂度空间复杂度 结果总结 题目 题目链接&#x1f517; 给你一个字符串 date&#xff0c;它的格式为 yyyy-mm-dd&#xff0c;表示一个公历日期。 date 可以重写为二进制表示&#xff0c;只需要将年、月、日分别转换为对应的二进制表示&a…

Spring实现输出带动态标签的日志

版权说明&#xff1a; 本文由博主keep丶原创&#xff0c;转载请保留此块内容在文首。 原文地址&#xff1a; https://blog.csdn.net/qq_38688267/article/details/144851857 文章目录 背景底层原理实现方案Tag缓存实现封装注解通过AOP实现日志缓存封装行为参数通用方法实现手动…

JAVA: 状态模式(State Pattern)的技术指南

1、简述 状态模式是一种行为型设计模式,允许对象在其内部状态改变时改变其行为。它将状态相关的行为抽取到独立的状态类中,使得增加新状态变得简单,且不影响其他状态。 设计模式样例:https://gitee.com/lhdxhl/design-pattern-example.git 本文将详细介绍状态模式的概念…

小程序基础 —— 02 微信小程序账号注册

微信小程序账号注册 小程序开发与网页开发不一样&#xff0c;在开始微信小程序开发之前&#xff0c;需要访问微信公众平台&#xff0c;注册一个微信小程序账号。 有了小程序的账号以后&#xff0c;才可以开发和管理小程序&#xff0c;后续需要通过该账号进行开发信息的设置、…

安卓入门十一 常用网络协议四

MQTT&#xff08;Message Queuing Telemetry Transport&#xff09; MQTT是一种轻量级的、发布/订阅模式的消息传输协议。它被设计用于在低带宽或不稳定网络环境下&#xff0c;实现物联网设备之间的可靠通信。 4.1 MQTT详细介绍 发布/订阅模式&#xff1a;MQTT 使用发布/订…

在 Swift 中使用 SQL 组合人员和地址数据

文章目录 摘要描述问题描述示例输入与输出 Swift 代码解决方案代码分析示例测试及结果时间复杂度空间复杂度总结 摘要 在本篇文章中&#xff0c;我们将讨论如何结合两个表——Person 和 Address&#xff0c;以便生成包含每个人的姓名和地址信息的结果表。如果某人的地址信息不…

AAL省电效果对比

AAL省电的原理主要是‌通过根据显示内容来降低背光&#xff0c;然后通过调节gamma来补偿显示亮度&#xff0c;从而达到省电的效果‌。具体来说&#xff0c;gamma值越高&#xff0c;灰度越低&#xff0c;图像越暗。因此&#xff0c;颜色越暗的图片越省电&#xff0c;这也是为什么…

ArcGIS中怎么进行水文分析?(思路介绍)

最近有人咨询&#xff0c;ArcGIS中怎么进行水文分析&#xff0c;大致的说一下河网提取的思路哈 解决思路&#xff1a;dem填洼→计算水流方向→计算水流累积矩阵→形成河网 dem填洼 计算水流方向 计算水流累积矩阵 用栅格计算器&#xff0c;设阈值&#xff08;自己多次尝试&…

Debian-linux运维-ssh配置(兼容Jenkins插件的ssh连接公钥类型)

系统版本&#xff1a;Debian 12.5、11.1 1 生成密钥对 可以用云服务商控制台生成的密钥对&#xff0c;也可以自己在客户端或者服务器上生成&#xff0c; 已经有密钥对就可以跳过这步 用户默认密钥文件路径为 ~/.ssh/id_rsa&#xff0c;可以在交互中指定路径&#xff0c;也可…

ZZNUOJ 1798:大小写判断(C/C++/Java)

题目描述 给定一个英文字母判断这个字母是大写还是小写。 输入 输入只包含一个英文字母c。 输出 如果c是大写字母,输出“upper”,否则输出“lower”。 样例输入 x 样例输出 lower 来源 蓝桥杯算法训练 常见的ASCII值 ASCII表中可以记下部分特殊的值(十进制)(字母从A到Z&am…

Wonder Dynamics技术浅析(二):人体姿态估计

Wonder Dynamics 的人体姿态估计模块旨在从图像或视频中检测并定位人体关键点&#xff08;如关节、肢体等&#xff09;&#xff0c;为后续的动作捕捉、虚拟角色动画等应用提供基础数据。 一、人体姿态估计概述 人体姿态估计是指从图像或视频中检测并定位人体关键点的位置&…