【代码随想录】刷题Day14

news2025/1/11 16:44:26

递归实现的一些理解

1.如果是链表的遍历其实不需要怎么思考;无非就是先定参数然后考虑是先操作后遍历还是先走到底再操作。 包括我之前在写链表的节点删除其实核心思路就是由于链表前面删除后面找不到的原理,以至于我们需要走到链表的底部再进行操作。

2.但是二叉树有两个指针指向左右子树,那么遍历的规则就变了,它有三个遍历模式:前中后序遍历。那么其实前序就当作是链表的先指向后操作;后序也可以当作是先到底后执行操作。

3.那么写递归时最重要的无非就是三个点,把握这三点就能直到递归实现到底如何思考:

  1. 确定递归函数的参数和返回值: 确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数, 并且还要明确每次递归的返回值是什么进而确定递归函数的返回类型。

  2. 确定终止条件: 写完了递归算法, 运行的时候,经常会遇到栈溢出的错误,就是没写终止条件或者终止条件写的不对,操作系统也是用一个栈的结构来保存每一层递归的信息,如果递归没有终止,操作系统的内存栈必然就会溢出。

  3. 确定单层递归的逻辑: 确定每一层递归需要处理的信息。在这里也就会重复调用自己来实现递归的过程。

1.二叉树递归

由于需要返回vector<int>,所以我们传入的参数为引用型参数

//前序遍历
class Solution {
public:
    void _preorderR(TreeNode* root,vector<int>& ret)
    {
        if(root==nullptr)
            return;
        ret.push_back(root->val);
        _preorderR(root->left,ret);
        _preorderR(root->right,ret);
    }
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> ret;
        _preorderR(root,ret);
        return ret;
    }
};

//后序遍历
class Solution {
public:
    void _preorderR(TreeNode* root,vector<int>& ret)
    {
        if(root==nullptr)
            return;
        _preorderR(root->left,ret);
        _preorderR(root->right,ret);
        ret.push_back(root->val);
    }
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> ret;
        _preorderR(root,ret);
        return ret;
    }
};

//中序遍历
class Solution {
public:
    void _preorderR(TreeNode* root,vector<int>& ret)
    {
        if(root==nullptr)
            return;
        _preorderR(root->left,ret);
        ret.push_back(root->val);
        _preorderR(root->right,ret);
    }
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> ret;
        _preorderR(root,ret);
        return ret;
    }
};

2.非递归遍历

前序遍历的非递归

1.首先我们要知道非递归用栈实现,所以我们保存节点用栈存储,那么大致思路就是遇到根就先进vector,再把这个根入栈,往左走。随后栈顶的节点pop出来往右走

2.如果cur和栈都是空,说明此时循环是结束的,因为我们要插入的节点已经没有了,并且栈中也没有要往右走。

3.在循环里,无非就是再套一个循环,判断条件就是cur是否为空,把cur节点值push_back到vector并且cur节点入栈,随后cur更新为左节点。

4.遍历中间节点和左节点的循环结束,我们此时走到左节点底,因此要遍历走右节点,那么右节点就是将在栈中的节点pop出更新cur为出栈的节点的右节点即可

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> ret;
        stack<TreeNode*> sT;
        TreeNode* cur =root;
        while(cur||!sT.empty())
        {
            while(cur)
            {
                ret.push_back(cur->val);
                sT.push(cur);
                cur=cur->left;
            }
            TreeNode* top = sT.top();
            sT.pop();
            cur = top->right;
        }
        return ret;
    }
};

中序遍历的非递归

其实和前序非递归写法基本一致,无非就是push_back不一样

1.对于前序遍历,我们是先得到根,所以优先在入栈位置就一定要保存好根节点

2.对于中序遍历不是这样的,我们需要左节点,因此等节点一直判断到左节点的底部,我们才需要将出栈的节点,也就是最左节点push_back到我们所想要的vector中保存即可

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> ret;
        stack<TreeNode*> sT;
        TreeNode* cur =root;
        while(cur||!sT.empty())
        {
            while(cur)
            {  
                sT.push(cur);
                cur=cur->left;
            }
            TreeNode* top = sT.top();
            ret.push_back(top->val);
            sT.pop();
            cur = top->right;
        }
        return ret;
    }
};

后序遍历的非递归

入栈的思路其实差不多,有一些差别的是push_back和判断是否为右节点的操作

1.如果栈顶的没有右节点说明此时这个节点可以出栈

2.如果栈顶的右节点存在但是右节点已经走过了,那么也可以出栈

3.此为的其他条件,都是说明 12 条件不成立,以至于我们需要的往右继续进行遍历入栈

5.那么其实 1和3 都已经知道怎么搞了,唯一还需要判断条件2,我们应该怎么样才能知道节点已经走过右边的子树呢?我们需要一个前驱节点,这个前驱节点是用来判断当前栈顶元素的右边是否为前驱,如果是那么说明走过了,以至于我们可以进行出栈顶操作和bush_back操作

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> ret;
        stack<TreeNode*> sT;
        TreeNode* cur = root;
        TreeNode* prev = nullptr;
        while(cur||!sT.empty())
        {
            while(cur)
            {  
                sT.push(cur);
                cur=cur->left;
            }
            TreeNode* top = sT.top();
            if(top->right==nullptr||top->right==prev)
            {
                ret.push_back(top->val);
                prev = sT.top();
                sT.pop();
            }
            else
                cur=top->right;
        }
        return ret;
    }
};

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

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

相关文章

【Android入门到项目实战-- 8.3】—— 如何解析XML格式数据

目录 一、准备工作 EasyWebServer 二、Pull解析方式 三、SAX解析方式 我们可以向服务器提交数据&#xff0c;也可以获取数据&#xff0c;但是数据交换的不仅仅是内容&#xff0c;还要对数据的属性、作用进行描述&#xff0c;当另一方收到数据消息后可以按照相同的结构规格进…

Android开发的《大众设计App》项目介绍

该《大众设计App》的功能介绍如下&#xff1a; 1、登录&注册功能 登录、注册页面效果如下所示&#xff1a; 2、用户信息修改功能 &#xff08;各个修改功能均已实现&#xff0c;因修改栏目较多不再逐一展示&#xff09; 3、设计衣服的功能 &#xff08;也是本App的核心…

Redis缓存穿透、击穿、雪崩问题及其解决方法

Redis缓存穿透、击穿、雪崩问题及其解决方法 1 缓存穿透1.1 概念及其解决思路1.2 编码解决商品查询的缓存穿透问题&#xff1a; 2 缓存雪崩问题及解决思路3 缓存击穿问题及解决思路3.1 利用互斥锁解决缓存击穿问题3.2 利用逻辑过期解决缓存击穿问题 1 缓存穿透 1.1 概念及其解…

光缆线路网的组网结构是怎样的

1 引言 根据GB 51158-2015《通信线路工程设计规范》&#xff0c;通信线路网包括长途线路、本地线路和接入线路&#xff0c;如图1所示。 图1 通信线路网的组成 根据传输媒质的不同&#xff0c;通信线路分为光缆线路和电缆线路。通信线路也经历了从架空明线到电缆线路再到光缆线路…

利用Google Colab免费使用GPU服务器详细攻略

目录 前言 一、Colab限额、提供的GPU类型 二、Colab的使用步骤&#xff08;如何使用免费GPU资源&#xff09; 1、添加Colaboratory 2、新建Colab、连接GPU、挂载Google Driver 3、项目上传文件并运行 三、快速下载/上传Google Drive文件的方法&#xff08;利用MultiClou…

【java】彻底剖析 Synchronized

文章目录 前言对象结构Monitor 对象Synchronized特征原子性可见性有序性可重入锁 锁升级的过程 前言 源码级别剖析Synchronized 对象结构 Synchronized是Java中的隐式锁&#xff0c;它的获取锁和释放锁都是隐式的&#xff0c;完全交由JVM帮助我们操作&#xff0c;在了解Sync…

Java面试题总结 | Java面试题总结9- RabbitMQ模块(持续更新)

RabbitMQ 文章目录 RabbitMQ为什么使用Rabbitmq而不是其他的消息队列为什么使用消息队列解耦异步削峰 消息队列有什么优缺点MQ的高可用保障单机模式 普通集群模式&#xff08;无高可用性&#xff09;镜像集群模式&#xff08;高可用性&#xff09; MQ如何保证不重复消费、幂等性…

ROS导航包Navigation中的 Movebase节点路径规划相关流程梳理

本文主要介绍ROS导航包Navigation中的 Movebase节点中的路径规划的相关流程&#xff0c;并对其进行梳理概括&#xff0c;同时本文也是《ROS局部路径规划器插件teb_local_planner规划流程概括总结》部分的前述文章。 1、接收到目标点信息goal 在接收到目标点goal之后&#xff0c…

JAVA医院管理云HIS统计报表子系统、系统管理字系统功能实现

一、统计报表子系统 统计报表子系统功能模块&#xff1a;包括门诊收入汇总、住院收入汇总、收费统计报表、收费明细报表、 缴款日报、门诊收费汇总、住院科室日志、住院结算汇总、医疗项目统计、检查项目统计、 检验项目统计、月末收支汇总、药品进销存统计。 &#xff08;1…

从零开始三端口DC-DC变换器

1、 题目解析 基本要求 &#xff08;1&#xff09; U S 50 V 、 I O 1.2 A U_S50V、I_O1.2A US​50V、IO​1.2A 条件下&#xff0c;变换器工作在模式I&#xff0c; U O 30 V 0.1 V &#xff0c; I B ≥ 0.1 A U_O30V0.1V&#xff0c;I_B≥0.1A UO​30V0.1V&#xff0c;IB​…

CleanMyMac X4.13.2最新版下载

现在cleanmymac x4.13.2中文版是大家首选的优秀mac清理软件。CleanMyMac集合了多种功能&#xff0c;几乎可以满足用户所有的清洁需求。它不仅包含各种清理功能&#xff0c;还具有卸载、维护、扩展、碎纸机等实用功能&#xff0c;可同时替代多种工具。它可以清理、优化、维护和监…

边缘人工智能——nanodet模型实践指引,从标注数据集到实现部署文件

内容概述 首先获得一个合适的nanodet模型版本&#xff0c;配置nanodet适用的环境&#xff0c;然后对网上公开的生数据集进行重新标注&#xff0c;配置nanodet并进行训练&#xff0c;.pth到.onnx的模型转化及简化&#xff0c;编写推理文件。 文章着重于实践方向指引&#xff0c;…

【LeetCode股票买卖系列:123. 买卖股票的最佳时机 III 暴力递归=>记忆化搜索=>动态规划】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

基于Flask+Bootstrap+机器学习的南昌市租房价格预测系统

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

图片分类:精细化分类,(Fine-Grained Categorization) 基于人的行为的精细化分类

文字大纲 简介数据集常用数据集方法1 : 强监督方法2 : 弱监督Two Level Attention Model双线性网络 Bilinear CNN model参考文献和学习路径简介 细粒度图像识别 (fine-grained image recognition),即 精细化分类。 细粒度图像分类(Fine-Grained Categorization), 又被称作…

2023年05月IDE流行度最新排名

点击查看最新IDE流行度最新排名&#xff08;每月更新&#xff09; 2023年05月IDE流行度最新排名 顶级IDE排名是通过分析在谷歌上搜索IDE下载页面的频率而创建的 一个IDE被搜索的次数越多&#xff0c;这个IDE就被认为越受欢迎。原始数据来自谷歌Trends 如果您相信集体智慧&am…

感知机介绍

1&#xff0c;数学定义&#xff1a; Note:<>在数学中通常指求期望的意思。 假设我们用感知机区分cat和dog&#xff0c;使用下面三个特征&#xff1a;x1: color of hair&#xff1b;x2:length of leg&#xff1b;x3:volume of head。cat 用1表示&#xff0c;dog用-1表示&…

Golang每日一练(leetDay0053)

目录 155. 最小栈 Min Stack &#x1f31f;&#x1f31f; 156. 二叉树的上下翻转 Binary Tree Upside Down &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java每日一练 专栏 …

ArrayList集合扩容机制入门

首先&#xff0c;ArrayList集合存储的数据在底层是一个数组&#xff08;名字elementData&#xff09;&#xff0c;这个数组是Object的数组&#xff0c;因为是Object数组&#xff0c;所以集合啥都可以装。 讲解ArrayList的扩容机制&#xff0c;要从ArrayList的构造器来分类&…

Spark RDD 持久化(CheckPoint 检查点)

RDD Cache 缓存 RDD 通过 Cache 或者 Persist 方法将前面的计算结果缓存&#xff0c;默认情况下会把数据以缓存 在 JVM 的堆内存中。但是并不是这两个方法被调用时立即缓存&#xff0c;而是触发后面的 action 算 子时&#xff0c;该 RDD 将会被缓存在计算节点的内存中 // cach…