代码随想录第十八天 513 找树左下角的值 112 路径之和 106 从中序与后序遍历序列构造二叉树

news2025/1/12 16:11:02

LeetCode 513 找树左下角的值 

题目描述

给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。

假设二叉树中至少有一个节点。

示例 1:

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

示例 2:

输入: [1,2,3,4,null,5,6,null,null,7]
输出: 7

思路 

     1.确定递归函数的参数和返回值

参数必须有要遍历的树的根节点,还有就是一个int型的变量用来记录最长深度。 这里就不需要返回值了,所以递归函数的返回类型为void。

本题还需要类里的两个全局变量,maxLen用来记录最大深度,result记录最大深度最左节点的数值。

代码如下:

int maxDepth = INT_MIN;   // 全局变量 记录最大深度
int result;       // 全局变量 最大深度最左节点的数值
void traversal(TreeNode* root, int depth)

      2.确定终止条件

当遇到叶子节点的时候,就需要统计一下最大的深度了,所以需要遇到叶子节点来更新最大深度。

代码如下:

if (root->left == NULL && root->right == NULL) {
    if (depth > maxDepth) {
        maxDepth = depth;           // 更新最大深度
        result = root->val;   // 最大深度最左面的数值
    }
    return;
}

      3.确定单层递归的逻辑

在找最大深度的时候,递归的过程中依然要使用回溯,代码如下:

                    // 中
if (root->left) {   // 左
    depth++; // 深度加一
    traversal(root->left, depth);
    depth--; // 回溯,深度减一
}
if (root->right) { // 右
    depth++; // 深度加一
    traversal(root->right, depth);
    depth--; // 回溯,深度减一
}
return;

代码实现  

/**
 * 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:
    int maxDepth = INT_MIN;
    int result;
    void traversal(TreeNode* root,int depth){
        if(root -> left == NULL && root -> right == NULL){
           if(depth > maxDepth){
               maxDepth = depth;
               result = root -> val;
           }
           return;     
        }
        if(root -> left){
            depth++;
            traversal(root -> left,depth);
            depth--;
        }
        if(root -> right){
            depth++;
            traversal(root -> right,depth);
            depth--;
        }
        return;
    }
    int findBottomLeftValue(TreeNode* root) {
        int depth;
        traversal(root,depth);
        return result;
    }
};

LeetCode 112 路径之和 

 题目描述

给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。

叶子节点 是指没有子节点的节点。

示例 1:

输入:root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22
输出:true
解释:等于目标和的根节点到叶节点路径如上图所示。

示例 2:

输入:root = [1,2,3], targetSum = 5
输出:false
解释:树中存在两条根节点到叶子节点的路径:
(1 --> 2): 和为 3
(1 --> 3): 和为 4
不存在 sum = 5 的根节点到叶子节点的路径。

示例 3:

输入:root = [], targetSum = 0
输出:false
解释:由于树是空的,所以不存在根节点到叶子节点的路径。

 思路

1.确定递归函数的参数和返回类型

参数:需要二叉树的根节点,还需要一个计数器,这个计数器用来计算二叉树的一条边之和是否正好是目标和,计数器为int型。

再来看返回值,递归函数什么时候需要返回值?什么时候不需要返回值?这里总结如下三点:

  • 如果需要搜索整棵二叉树且不用处理递归返回值,递归函数就不要返回值。(这种情况就是本文下半部分介绍的113.路径总和ii)
  • 如果需要搜索整棵二叉树且需要处理递归返回值,递归函数就需要返回值。 
  • 如果要搜索其中一条符合条件的路径,那么递归一定需要返回值,因为遇到符合条件的路径了就要及时返回。(本题的情况)

而本题我们要找一条符合条件的路径,所以递归函数需要返回值,及时返回,那么返回类型是什么呢?

如图所示:

112.路径总和

图中可以看出,遍历的路线,并不要遍历整棵树,所以递归函数需要返回值,可以用bool类型表示。

所以代码如下:

bool traversal(treenode* cur, int count)   // 注意函数的返回类型

2.确定终止条件

首先计数器如何统计这一条路径的和呢?

不要去累加然后判断是否等于目标和,那么代码比较麻烦,可以用递减,让计数器count初始为目标和,然后每次减去遍历路径节点上的数值。

如果最后count == 0,同时到了叶子节点的话,说明找到了目标和。

如果遍历到了叶子节点,count不为0,就是没找到。

递归终止条件代码如下:

if (!cur->left && !cur->right && count == 0) return true; // 遇到叶子节点,并且计数为0
if (!cur->left && !cur->right) return false; // 遇到叶子节点而没有找到合适的边,直接返回

     3.确定单层递归的逻辑

因为终止条件是判断叶子节点,所以递归的过程中就不要让空节点进入递归了。

递归函数是有返回值的,如果递归函数返回true,说明找到了合适的路径,应该立刻返回。

代码如下:

if (cur->left) { // 左 (空节点不遍历)
    // 遇到叶子节点返回true,则直接返回true
    if (traversal(cur->left, count - cur->left->val)) return true; // 注意这里有回溯的逻辑
}
if (cur->right) { // 右 (空节点不遍历)
    // 遇到叶子节点返回true,则直接返回true
    if (traversal(cur->right, count - cur->right->val)) return true; // 注意这里有回溯的逻辑
}
return false;

 代码实现

class Solution {
private:
    bool traversal(TreeNode* cur, int count) {
        if (!cur->left && !cur->right && count == 0) return true; // 遇到叶子节点,并且计数为0
        if (!cur->left && !cur->right) return false; // 遇到叶子节点直接返回

        if (cur->left) { // 左
            count -= cur->left->val; // 递归,处理节点;
            if (traversal(cur->left, count)) return true;
            count += cur->left->val; // 回溯,撤销处理结果
        }
        if (cur->right) { // 右
            count -= cur->right->val; // 递归,处理节点;
            if (traversal(cur->right, count)) return true;
            count += cur->right->val; // 回溯,撤销处理结果
        }
        return false;
    }

public:
    bool hasPathSum(TreeNode* root, int sum) {
        if (root == NULL) return false;
        return traversal(root, sum - root->val);
    }
};

LeetCode 106 从中序与后序遍历序列构造二叉树

题目描述

给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。

示例 1:

输入:inorder = [9,3,15,20,7], postorder = [9,15,7,20,3]
输出:[3,9,20,null,null,15,7]

示例 2:

输入:inorder = [-1], postorder = [-1]
输出:[-1]

思路

中序:9 3 15 20 7   左中右

后续:9 15 7 20 3  左右中

遍历二叉树的思路是,首先后续数组的最后一个元素一定是根节点,找到根节点之后切割中序数组,根节点前面的数组为左子树,后面的为右子树。根据中序数组左子树和右子树的元素个数,切割后序数组,例如左子树一共有3个数字,那么后续数组的前三个元素就是左子树,第四个到第size-1个就是右子树,然后再找后序数组左子树和右子树的最后一个元素,这个元素就是左子树或右子树的中间节点。依此类推,中间节点左右两边的数据再分为左子树和右子树,直到所有元素都遍历了为止。

106.从中序与后序遍历序列构造二叉树

代码思路如下:

  • 第一步:如果数组大小为零的话,说明是空节点了。

  • 第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。

  • 第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点

  • 第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)

  • 第五步:切割后序数组,切成后序左数组和后序右数组

  • 第六步:递归处理左区间和右区间

代码实现

/**
 * 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* buildTree(vector<int>& inorder, vector<int>& postorder) {
        if(postorder.size() == 0) return NULL;
        int rootvalue = postorder[postorder.size() - 1];
        TreeNode* root = new TreeNode(rootvalue);
        if(postorder.size() == 1) return root;
        int index = 0;
        for(index = 0;index < inorder.size();index++){
            if(inorder[index] == rootvalue) break; 
        }
        vector<int> leftinorder;
        vector<int> rightinorder;
        vector<int> leftpostorder;
        vector<int> rightpostorder;
        for(int i = 0;i < index;i++){
            leftpostorder.push_back(postorder[i]);
        } 
        for(int i = index;i < postorder.size()-1;i++){
            rightpostorder.push_back(postorder[i]);
        }
        for(int i = 0;i < index;i++){
            leftinorder.push_back(inorder[i]);
        }
        for(int i = index+1;i < postorder.size();i++){
            rightinorder.push_back(inorder[i]);
        }
        root -> left = buildTree(leftinorder,leftpostorder);
        root -> right = buildTree(rightinorder,rightpostorder);
        return root;
    }
};

ps:这里已知前序,中序或者中序,后序都可以构造唯一的二叉树,但是前序和后序不可以,因为前序和后序的左子树,右子树都是相连的,不可以构造唯一的二叉树。

LeetCode  654 最大二叉树

题目描述 

给定一个不重复的整数数组 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]

思路

本题的思路和上一题的思路基本一致,刚开始没有判断nums的size是否为0,会有如下报错。

刚开始的nums不为空,递归几轮之后可能数组就会为空,所以还是要判断,size为1也要判断。

代码实现

/**
 * 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) {
        if(nums.size() == 0) return NULL;
        int maxvalue = 0;
        int maxindex;
        for(int i = 0;i < nums.size();i++){
            if(nums[i] > maxvalue){
                maxvalue = nums[i];
                maxindex = i;
            }
        }
        TreeNode* root = new TreeNode(maxvalue);
        if(nums.size() == 1) return root;
        vector<int> lefttree;
        vector<int> righttree;
        for(int i = 0;i < maxindex;i++){
            lefttree.push_back(nums[i]);
        }
        for(int i = maxindex+1;i < nums.size();i++){
            righttree.push_back(nums[i]);
        }
        root -> left = constructMaximumBinaryTree(lefttree);
        root -> right = constructMaximumBinaryTree(righttree);
        return root;
    }
};

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

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

相关文章

多级缓存

一、多级缓存 传统的缓存策略一般是请求到达Tomcat后&#xff0c;先查询Redis&#xff0c;如果未命中则查询数据库&#xff0c;如图&#xff1a; 存在下面的问题&#xff1a; •请求要经过Tomcat处理&#xff0c;Tomcat的性能成为整个系统的瓶颈 •Redis缓存失效时&#xff…

打折:阿里云国外服务器价格购买优惠活动

阿里云国外服务器优惠活动「全球云服务器精选特惠」&#xff0c;国外服务器租用价格24元一个月起&#xff0c;免备案适合搭建网站&#xff0c;部署独立站等业务场景&#xff0c;阿里云服务器网aliyunfuwuqi.com分享阿里云国外服务器优惠活动&#xff1a; 全球云服务器精选特惠…

77. 组合 - 力扣(LeetCode)

题目描述 给定两个整数 n 和 k&#xff0c;返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任何顺序 返回答案。 输入示例 n 4, k 2输出示例 [[2,4],[3,4],[2,3],[1,2],[1,3],[1,4], ]解题思路 我们使用回溯、深度优先遍历的思想&#xff0c;我们使用一个栈 path…

linux驱动(八):block,net

本文主要探讨210的block驱动和net驱动。 block 随机存取设备且读写是按块进行,缓冲区用于暂存数据,达条件后一次性写入设备或读到缓冲区 块设备与字符设备:同一设备支持块和字符访问策略,块设备驱动层支持缓冲区,字符设备驱动层没有缓冲 块设备单位:扇…

Leetcode的AC指南 —— 栈与队列:20. 有效的括号

摘要&#xff1a; **Leetcode的AC指南 —— 栈与队列&#xff1a;20. 有效的括号 **。题目介绍&#xff1a;给定一个只包括 ‘(’&#xff0c;‘)’&#xff0c;‘{’&#xff0c;‘}’&#xff0c;‘[’&#xff0c;‘]’ 的字符串 s &#xff0c;判断字符串是否有效。 有效字…

基于JavaWeb+SSM+Vue智能社区服务小程序系统的设计和实现

基于JavaWebSSMVue智能社区服务小程序系统的设计和实现 滑到文末获取源码Lun文目录前言主要技术系统设计功能截图订阅经典源码专栏Java项目精品实战案例《500套》 源码获取 滑到文末获取源码 Lun文目录 目录 1系统概述 1 1.1 研究背景 1 1.2研究目的 1 1.3系统设计思想 1 2相…

【计算机硬件】4、练习题

根据冯诺依曼原理&#xff0c;计算机硬件的基本组成是&#xff08;&#xff09; A.输入、输出设备、运算器、控制器、存储器 B.磁盘、软盘、内存、CPU、显示 C.打印机、触摸屏、键盘、软盘 D.鼠标、打印机、主机、显示器、存储器 CPU执行算术运算或者逻辑运算时&#xff0c;常…

class_14:继承

C继承有点类似于c语言 结构体套用 #include <iostream> #include <string> using namespace std;//基类,父类 class Vehicle{ public:string type;string contry;string color;double price;int numOfWheel;void run();void stop(); };//派生类&#xff0c…

Python基础第五篇(Python数据容器)

文章目录 一、数据容器入门二、数据容器 list 列表(1),list 列表定义(2),list列表的索引(3),list列表的常见操作(4),list列表的遍历 三、数据容器&#xff1a;tuple&#xff08;元组&#xff09;(1),tuple元组定义(2),tuple元组的索引(3),tuple元组的常见操作(4),tuple元组的遍…

力扣【四数之和】

一、题目描述 18. 四数之和 给你一个由 n 个整数组成的数组 nums &#xff0c;和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] &#xff08;若两个四元组元素一一对应&#xff0c;则认为两个四元组重复&#x…

PyQt5 快速入门(一)

第一节按钮控件,文本控件,输入框,app图标 文章目录 一.GUI按钮控件 二.文本控件 三.输入框 四.让窗口显示在屏幕中央 五.让窗口显示在屏幕中央 总结 一.GUI按钮控件 import sys from PyQt5.QtWidgets import QApplication, QWidget, QPushButtonif __name__ __main__:app …

python爬虫知识点:5种线程锁

嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! python更多源码/资料/解答/教程等 点击此处跳转文末名片免费获取 线程安全 线程安全是多线程或多进程编程中的一个概念&#xff0c;在拥有共享数据的多条线程并行执行的程序中&#xff0c;线程安全的代码会通过同步机制保证各个…

Python使用graphviz绘制模块间数据流

graphviz官方参考链接&#xff1a; http://www.graphviz.org/documentation/ https://graphviz.readthedocs.io/en/stable/index.html 文章目录 需求描述环境配置实现思路代码实现 需求描述 根据各模块之间的传参关系绘制出数据流&#xff0c;如下图所示&#xff1a; 并且生成…

Redis(01)——常用指令

基础指令 select 数字&#xff1a;切换到其他数据库flushdb&#xff1a;清空当前数据库flushall&#xff1a;清空所有数据库dbsize&#xff1a;查看数据库大小exists key1[key2 …]&#xff1a;判断当前的key是否存在keys *&#xff1a;查看所有的keyexpire key 时间&#xff…

深入Matplotlib:画布分区与高级图形展示【第33篇—python:Matplotlib】

文章目录 Matplotlib画布分区技术详解引言方法一&#xff1a;plt.subplot()方法二&#xff1a;简略写法方法三&#xff1a;plt.subplots()实例展示添加更多元素 进一步探索Matplotlib画布分区自定义子图布局3D子图结语 Matplotlib画布分区技术详解 引言 Matplotlib是一个强大…

第13节-简历中的开放性问题

(点击即可收听) 不少公司的开放式题目每年不会有太大的变化&#xff0c;所以在答题前可先去相关求职论坛看看这些公司往年的问题&#xff0c;分析和思考自己应当怎么回答 开放式问题回答技巧 开放式问题主要考察的是求职者的求职动机、解决问题的能力、创造力等软实力&#xff…

C++入门之基础语法

目录 一.关键字 二.命名空间 2.1命名空间域 2.2展开命名空间域 using namespace bit 使用using将命名空间中的某个成员引入 2.3 头文件#include 2.3.1 头文件的展开和命名空间的展开区别 2.4 C的标准的库命名空间std 2.5 命名空间的套娃 三. C输入输出 3.1 流插入co…

线性代数:逆矩阵

目录 伴随阵 逆矩阵 证明&#xff1a;AA* A*A |A|E 证明&#xff1a;|A| 0 > |A*| 0 伴随阵 逆矩阵 证明&#xff1a;AA* A*A |A|E 证明&#xff1a;|A| 0 > |A*| 0

项目管理该考哪个证书❓NPDP还是软考❓

有小伙伴在纠结是要考NPDP认证呢还是考软考呢❓ 今天小编要给大家好好说说NPDP认证❗️ &#x1f4a1;NPDP全称New Product Development Professional&#xff0c;也就是产品经理国际资格认证。 &#x1f525;NPDP是国际公认的为一的新产品开发专业认证&#xff0c;是集理论、方…

JVM系列-2.字节码文件详解

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱吃芝士的土豆倪&#xff0c;24届校招生Java选手&#xff0c;很高兴认识大家&#x1f4d5;系列专栏&#xff1a;Spring原理、JUC原理、Kafka原理、分布式技术原理、数据库技术、JVM原理&#x1f525;如果感觉博主的文…