二叉树16:找树左下角的值

news2024/11/15 17:31:57

主要是我自己刷题的一些记录过程。如果有错可以指出哦,大家一起进步。
转载代码随想录
原文链接:
代码随想录
leetcode链接:513.找树左下角的值

题目:

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

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

示例:

示例 1:

在这里插入图片描述

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

示例 2:

在这里插入图片描述

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

提示:

二叉树的节点个数的范围是 [1,10^4]
-2^31 <= Node.val <= 2^31 - 1 

思路:

本题要找出树的最后一行的最左边的值。此时大家应该想起用层序遍历是非常简单的了,反而用递归的话会比较难一点。

我们依然还是先介绍递归法。

咋眼一看,这道题目用递归的话就就一直向左遍历,最后一个就是答案呗?
没有这么简单,一直向左遍历到最后一个,它未必是最后一行啊。
我们来分析一下题目:在树的最后一行找到最左边的值。首先要是最后一行,然后是最左边的值。
如果使用递归法,如何判断是最后一行呢,其实就是深度最大的叶子节点一定是最后一行。
如果对二叉树深度和高度还有点疑惑的话,请看:110.平衡二叉树。
所以要找深度最大的叶子节点。

那么如何找最左边的呢?可以使用前序遍历(当然中序,后序都可以,因为本题没有 中间节点的处理逻辑,只要左优先就行),保证优先左边搜索,然后记录深度最大的叶子节点,此时就是树的最后一行最左边的值。

递归三部曲:

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;

完整代码如下:

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) {
        traversal(root, 0);
        return result;
    }
};

当然回溯的地方可以精简,精简代码如下:

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) {
            traversal(root->left, depth + 1); // 隐藏着回溯
        }
        if (root->right) {
            traversal(root->right, depth + 1); // 隐藏着回溯
        }
        return;
    }
    int findBottomLeftValue(TreeNode* root) {
        traversal(root, 0);
        return result;
    }
};

如果对回溯部分精简的代码 不理解的话,可以看这篇257. 二叉树的所有路径

迭代法

本题使用层序遍历再合适不过了,比递归要好理解得多!
只需要记录最后一行第一个节点的数值就可以了。
如果对层序遍历不了解,看这篇二叉树:层序遍历登场!,这篇里也给出了层序遍历的模板,稍作修改就一过刷了这道题了。

代码如下:

class Solution {
public:
    int findBottomLeftValue(TreeNode* root) {
        queue<TreeNode*> que;
        if (root != NULL) que.push(root);
        int result = 0;
        while (!que.empty()) {
            int size = que.size();
            for (int i = 0; i < size; i++) {
                TreeNode* node = que.front();
                que.pop();
                if (i == 0) result = node->val; // 记录最后一行第一个元素
                if (node->left) que.push(node->left);
                if (node->right) que.push(node->right);
            }
        }
        return result;
    }
};

总结

本题涉及如下几点:

  • 递归求深度的写法,我们在110.平衡二叉树中详细的分析了深度应该怎么求,高度应该怎么求。
  • 递归中其实隐藏了回溯,在257. 二叉树的所有路径中讲解了究竟哪里使用了回溯,哪里隐藏了回溯。
  • 层次遍历,在二叉树:层序遍历登场!深度讲解了二叉树层次遍历。 所以本题涉及到的点,我们之前都讲解过,这些知识点需要同学们灵活运用,这样就举一反三了。

自己的代码

class Solution {//迭代法,这个基本和他的代码一样了
public:
    int findBottomLeftValue(TreeNode* root) {
		if (!root) return -1;
		queue<TreeNode*> que;
		int result;
		que.push(root);
		while (!que.empty()) {
			int size = que.size();
			for (int i = 0; i < size; i++) {
				if (i == 0) result = que.front()->val;
				auto temp = que.front();
				que.pop();
				if (temp->left) que.push(temp->left);
				if (temp->right) que.push(temp->right);
			}
		}
		return result;
	}
};

class Solution {//递归法,我这个主要是深度优先搜索,其实就是前序遍历来做处理,
public:
    int result{-1};

	void dfs(TreeNode* node, int curDepth, int& maxDepth) {
		if (curDepth > maxDepth) { 
			result = node->val; 
			maxDepth = curDepth; 
		}
		if(node->left) dfs(node->left, curDepth+1, maxDepth);
		if (node->right) dfs(node->right, curDepth + 1, maxDepth);
	}

	int findBottomLeftValue(TreeNode* root) {
		if (!root) return -1;
		int curDepth = 0;
		int maxDepth = -1;
		dfs(root, curDepth, maxDepth);
		return result;
	}
};

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

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

相关文章

Android每周一轮子:Nvwa(热修复)

前言 &#xff08;废话&#xff09; 最近发现了一个问题&#xff0c;一些平时博客写的很多的程序员&#xff0c;反倒在日常的工作中&#xff0c;却是业务写的很一般&#xff0c;只会摆理论的人&#xff0c;甚至还跑出来教别人如何找工作&#xff0c;如何做架构&#xff0c;其实…

2022年终总结:少年不惧岁月长,彼方尚有荣光在。

2022年终总结&#xff1a;少年不惧岁月长&#xff0c;彼方尚有荣光在。 &#x1f3ac; 博客主页&#xff1a;王同学要努力 &#x1f3ac;个人简介&#xff1a;大三小白&#xff0c;喜欢前端 &#xff0c;热爱分享 &#x1f3a5; 本文由 王同学要努力 原创&#xff0c;首发于…

Eureka 注册中心

Eureka 注册中心目录概述需求&#xff1a;设计思路实现思路分析1.快速上手2.增加 Maven 依赖3.Client端配置注册中心Server端配置注册中心参考资料和推荐阅读Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip ha…

R 语言 管道操作符

背景 关于代码的简洁性,就是你使用了比较简化的高级操作符,但是有时候会增加代码的可读性。这种可读性在于你是否真正的去了解R的高级语法。你了解高级语法,他就不难,你不了解,他就难,可读性差。 这里我们来讲解一下,关于管道操作符,使R语言编程简化一些。 管道操作…

【登录流程执行逻辑】

1)整体流程图 2.main.js是入口&#xff0c;里面require("permission")时会触发方法体 在进行require("权限时")&#xff0c;会进行一系列初始化。 重定向。 接着走login方法。 vuex其实就是store。 触发vuex里面的方法: await store.dispatch(user/getInf…

CDN消耗速度太快,解决办法

前段时间发现我网站的CDN消耗速度太快了&#xff0c;20多块钱100G的流量&#xff0c;半个月甚至十几天左右都消耗完了。 于是我看CDN的访问ip并不多&#xff0c;发现大部分消耗的都是静态资源&#xff0c;js等文件。 后来找到了解决办法&#xff0c;目前100G还有这么多 方法 …

基于MVC的网上汽车城网站平台开发

摘要 随着现代都市生活节奏的不断加快、网络覆盖面的日益扩大&#xff0c;越来越多的人们加入了网上购物的行列。如今&#xff0c;网购已经成为人们生活的一部分。本系统主要是使用 B/S架构开发出的一个基于 ASP.NET的网上汽车城网站平台开发。前台页面使用CSSDIV&#xff0c;后…

Torch包学习

创建 torch.from_numpy(ndarray) → Tensor&#xff1a;将numpy.ndarray 转换为pytorch的 Tensor。两者共享内存。返回的张量不能改变大小。orch.linspace(start, end, steps100, outNone) → Tensor&#xff1a;生成一个 从start 到 end 的tensor。tensor的长度为steps。包括…

JVM【字节码与类的加载篇】

Class文件结构 字节码文件的跨平台性(了解) 1.Java语言&#xff1a;跨平台的语言 当Java源代码成功编译为字节码后&#xff0c;如果想在不同的平台上运行&#xff0c;则无须再次编译这个优势不再那么吸引人了。Python PHP perl ruby lisp等有强大的解释器跨平台似乎已经快成…

二叉树的遍历大全(前序,中序,后序)+(递归,迭代,Morris方法)

文章目录二叉树的前序遍历递归迭代Morris遍历二叉树的中序遍历递归迭代Morris遍历二叉树的后序遍历递归迭代Morris遍历二叉树的前序遍历 力扣传送门&#xff1a; https://leetcode.cn/problems/binary-tree-preorder-traversal/description/ 递归 递归的解法非常简单&#x…

快过年了,Python实现12306查票以及自动购票....

嗨害大家好鸭&#xff01;我是小熊猫~ 明天就是2023年啦~ 还有谁像我小熊猫一样没有回家的&#xff1f; 这次康康能不能12306抢票回家&#xff01;&#xff01;&#xff01; Python实现12306查票以及自动购票 [代码来源]: 青灯教育-自游老师 [环境使用]: Python 3.8Pycha…

构造函数和原型

1、概述 在典型的 OOP 的语言中&#xff08;如 Java&#xff09;&#xff0c;都存在类的概念&#xff0c;类就是对象的模板&#xff0c;对象就是类的实例&#xff0c;但在 ES6之前&#xff0c; JS 中并没用引入类的概念。ES6&#xff0c; 全称 ECMAScript 6.0 &#xff0c;201…

计算机组成原理实验——三、存储器实验

一、实验目的 1.掌握存储器的工作原理和接口。 2.掌握存储器的实现方法和初始化方法。 3.掌握RISC-V中存储器的存取方式。 二、实验内容 1.利用vivado IP核创建6432的ROM&#xff0c;并在 系数文件中设置数据为123489ab&#xff1b; 2.利用vivado IP核创建6432的RAM&#xf…

猿如意---初学者的一盏明灯---程序员的宝藏app

&#x1f680;write in front&#x1f680; &#x1f4dd;个人主页&#xff1a;认真写博客的夏目浅石. &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd;​ &#x1f4e3;系列专栏&#xff1a;我的CSDN活动之旅 &#x1f4ac;总结&#xff1a;希望你看完…

Rabbit客户端操作不同交换机[包含延迟类型]

文章目录一&#xff1a;direct-直投交换机0.0: 说明 --- 只有队列和交换机绑定&#xff0c;且routing key路由键一致才会收到消息1.1: 先后创建两个队列1.2: 队列绑定Direct交换机&#xff0c;和routing key1.3: 未指明路由键&#xff1a;1.4: 指明路由键1.5: 两个队列绑定一个…

Python中基本输入和输出

文章目录前言一、使用input()函数输入二、使用print()函数输出前言 从我们接触第一个Python程序开始&#xff0c;就一直在使用 print() 函数向屏幕上输出一些字符&#xff0c;如下图代码所示&#xff1a; print() 函数就是Python的基本输出函数。那既然有输出&#xff0c;肯定…

[牛客复盘] 牛客2022跨年场 20221212

[牛客复盘] 牛客2022跨年场 20221212 一、本周周赛总结二、 A 猜群名1. 题目描述2. 思路分析3. 代码实现三、B 分赃1. 题目描述2. 思路分析3. 代码实现四、C 翻卡牌1. 题目描述2. 思路分析3. 代码实现五、D ygg的分数运算1. 题目描述2. 思路分析3. 代码实现六、E 摇色子1. 题目…

多线程生产者消费者——分别使用条件变量、信号量实现

生产者消费者 概念 生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯&#xff0c;而通过阻塞队列来进行通讯&#xff0c;所以生产者生产完数据之后不用等待消费者处理&#xff0c;直接扔给阻塞队列&#xff0c;消费者不…

超好用!win10安装Eiseg标注软件及使用(CPU版本)

写在前面的话 众所周知&#xff0c;标注分割掩膜的软件一般使用labelme&#xff0c;但是一个一个点太麻烦了&#xff0c;工作量太大&#xff0c;&#xff0c;之前&#xff0c;我的思路就是先标少量的数据然后训练个初始模型&#xff0c;再用初始模型对剩下的图像预测掩膜&…

【闲聊杂谈】深入理解Spring Security设计原理

1、什么是Spring Security 顾名思义&#xff0c;Security的意思是安全&#xff0c;本质上就是一个很纯粹的权限管理框架&#xff0c;提供认证和授权两大核心功能。在目前主流的Spring生态中的项目&#xff0c;说到安全框架&#xff0c;基本上SpringSecurity是首选。当然&#…