《剑指 Offer》专项突破版 - 面试题 49、50 和 51 : 详解与二叉树中路径相关的面试题(C++ 实现)

news2024/11/28 14:40:54

目录

面试题 49 : 从根节点到叶节点的路径数字之和

面试题 50 : 向下的路径节点值之和

面试题 51 : 节点值之和最大的路径


 


面试题 49 : 从根节点到叶节点的路径数字之和

题目

在一棵二叉树中所有节点都在 0~9 的范围之内,从根节点到叶节点的路径表示一个数字。求二叉树中所有路径表示的数字之和。例如,下图中的二叉树有 3 条从根节点到叶节点的路径,它们分别表示数字 395、391 和 302,这 3 个数字之和是 1088。

分析

首先考虑如何计算路径表示的数字。顺着指向子节点的指针路径向下遍历二叉树,每到达一个节点,就相当于在路径表示的数字末尾添加一个数字。例如,在最开始到达根节点,此时路径表示数字 3(0 x 10 + 3 = 3)。然后到达节点 9,此时路径表示数字 39(3 x 10 + 9 = 39)。然后向下到达节点 5,此时路径表示数字 395(39 x 10 + 5 = 395)。

这就是说,每当遍历到一个节点时都计算从根节点到当前节点的路径表示的数字。如果这个节点还有子节点,就把这个值传下去继续遍历它的子节点。先计算到当前节点为止的路径表示的数字,再计算它的子节点的路径表示的数字,这实质上就是典型的二叉树前序遍历

代码实现

class Solution {
public:
    int sumNumbers(TreeNode* root) {
        if (root == nullptr)
            return 0;
        
        return dfs(root, 0);
    }
private:
    int dfs(TreeNode* root, int pathNum) {
        pathNum = pathNum * 10 + root->val;
        if (root->left == nullptr && root->right == nullptr)
            return pathNum;
        
        int sum = 0;
        if (root->left)
            sum += dfs(root->left, pathNum);
        
        if (root->right)
            sum += dfs(root->right, pathNum);
        
        return sum;
    }
};

解题小经验

与二叉树中路径相关的面试题很多,通常这些面试题都可以用深度优先搜索解决,很少采用广度优先搜索。这是因为路径通常顺着指向子节点的指针方向,也就是纵向方向,这更加符合深度优先搜索的特点。广度优先搜索是从左到右遍历每层的节点,是横向的遍历。因此深度优先搜索更加适合解决与路径相关的面试题。


面试题 50 : 向下的路径节点值之和

题目

给定一棵二叉树和一个值 sum,求二叉树中节点值之和等于 sum 的路径的数目。路径的定义为二叉树中顺着指向子节点的指针向下移动所经过的节点,但不一定从根节点开始,也不一定到叶节点结束。例如,在下图所示的二叉树中有两条路径的节点值之和等于 8,其中第 1 条路径从节点 5 开始经过节点 2 到达节点 1,第 2 条从节点 2 开始到节点 6。

分析

在这个题目中,二叉树的路径的定义发生了改变,它不一定从根节点开始,也不一定到叶节点结束。路径的起始节点的不确定性给计算路径经过的节点值之和带来了很大的困难

虽然路径不一定从根节点开始,但仍然可以求得从根节点开始到达当前遍历节点的路径所经过的节点值之和。例如,从上图的二叉树的根节点 5 出发,一边顺着指向子节点的指针在路径上向下移动,一边累加当前已经经过的节点值之和。当到达节点 5 时,节点值之和为 5。假设先顺着指向左子节点的指针到达节点 2,此时路径经过的节点值之和为 7。如果再顺着指向右子节点的指针到达节点 6,此时路径经过的节点值之和为 15。

如果在路径上移动时把所有累加的节点值之和都保存下来,就容易知道是否存在从任意节点出发的值为给定 sum 的路径

前缀和 + 哈希表

例如,当到达上图中二叉树的根节点 5 时,从根节点开始的路径节点值之和是 5。当到达节点 2 时,从跟节点开始的路径经过的节点值之和是 7。当到节点 6 时,从根节点开始的路径经过的节点值之和为 13。由于要找出节点值之和为 8 的路径,而 13 与 5 的差值是 8,这就说明从节点 5 的下一个节点(即节点 2)开始到节点 6 结束的路径经过的节点值之和为 8。

有了前面的经验,就可以采用二叉树深度优先搜索来解决与路径相关的问题。当遍历到一个节点时,先累加从根节点开始的路径上的节点值之和,再计算它的左右子节点的路径的节点值之和。这就是典型的前序遍历的顺序。

代码实现

class Solution {
public:
    int pathSum(TreeNode* root, int targetSum) {
        if (root == nullptr)
            return 0;
​
        unordered_map<long, int> sumToCount;
        sumToCount[0] = 1;
        return dfs(root, targetSum, sumToCount, 0);
    }
private:
    int dfs(TreeNode* root, int targetSum,
        unordered_map<long, int>& sumToCount, long sum) 
    {
        sum += root->val;
        int counts = sumToCount[sum - targetSum];
        ++sumToCount[sum];
​
        if (root->left)
            counts += dfs(root->left, targetSum, sumToCount, sum);
​
        if (root->right)
            counts += dfs(root->right, targetSum, sumToCount, sum);
​
        --sumToCount[sum];
        return counts;
    }
};


面试题 51 : 节点值之和最大的路径

题目

在二叉树中将路径定义为顺着节点之间的连接从任意一个节点开始到达任意一个节点所经过的所有节点。路径中至少包含一个节点,不一定经过二叉树的根节点,也不一定经过叶节点。给定非空的一棵二叉树,请求出二叉树所有路径上节点值之和的最大值。例如,在下图所示的二叉树中,从节点 15 开始经过节点 20 到达节点 7 的路径的节点值之和为 42,是节点值之和最大的路径。

分析

这个题目中二叉树路径的定义又和前面的不同。这里的路径最主要的特点是路径有可能同时经过一个节点的左右子节点。例如,在上图中,一条路径可以经过节点 15、节点 20 和节点 7,即节点 20 的左子节点 15 和右子节点 7 同时在一条路径上。当然,路径也可以不同时经过一个节点的左右子节点。例如,在上图中,一条路径可以经过节点 -9、节点 20、节点 15 和节点 -3。

值得注意的是,如果一条路径同时经过某个节点的左右子节点,那么该路径一定不能经过它的父节点。例如,在上图中,经过节点 20、节点 15、节点 7 的路径不能经过节点 -9。

也就是说,当路径到达某个节点时,该路径既可以前往它的左子树,也可以前往它的右子树。但如果路径同时经过它的左右子树,那么就不能经过它的父节点

由于路径可能只经过左子树或右子树而不经过根节点,为了求得二叉树的路径上节点值之和的最大值,需要先求出左右子树中路径节点值之和的最大值(左右子树中的路径不经过当前节点),再求出经过根节点的路径节点值之和的最大值,最后对三者进行比较得到最大值。由于需要先求出左右子树的路径节点值之和的最大值,再求根节点,这看起来就是后序遍历

基于二叉树的后序遍历的参考代码如下所示

class Solution {
public:
    int maxPathSum(TreeNode* root) {
        maxSum = INT_MIN;
        dfs(root);
        return maxSum;
    }
private:
    int dfs(TreeNode* root) {
        if (root == nullptr)
            return 0;
        
        int left = max(0, dfs(root->left));  
        int right = max(0, dfs(root->right)); 
        maxSum = max(maxSum, root->val + left + right);
        // 注意:如果一条路径同时经过某个节点的左右子节点,
        // 那么该路径一定不能经过它的父节点
        return root->val + max(left, right);  
    }
private:
    int maxSum;
};

二叉树的直径

题目

给你一棵二叉树的根节点,返回该树的直径。

二叉树的直径是指树中任意两个节点之间最长路径的长度。这条路径可能经过也可能不经过根节点 root

两节点之间路径的长度由它们的边数表示。

示例

输入:root = [1,2,3,4,5]
输出:3
解释:3 ,取路径 [4,2,1,3] 或 [5,2,1,3] 的长度

代码实现

class Solution {
public:
    int diameterOfBinaryTree(TreeNode* root) {
        diameter = INT_MIN;
        dfs(root);
        return diameter;
    }
private:
    int dfs(TreeNode* root) {
        if (root == nullptr)
            return -1;
        
        int left = dfs(root->left);  
        int right = dfs(root->right);
        diameter = max(diameter, 2 + left + right);
        return 1 + max(left, right);
    }
private:
    int diameter;
};

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

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

相关文章

5G车载路由器引领无人驾驶车联网应用

随着无人驾驶技术的不断发展&#xff0c;车联网正逐渐成为实现智能交通的重要组成部分。5G车载路由器将在车联网的应用中起到至关重要的作用&#xff0c;它能够满足无人驾驶应用的低时延、高速率和实时控制等需求&#xff0c;进一步推动无人驾驶车联网技术。 5G路由器具备低时延…

ACK One:构建混合云同城容灾系统

作者&#xff1a;蔡靖 对于当前业务运行在 IDC 内的 Kubernetes 集群中&#xff0c;希望通过云计算为云下业务提供同城灾备的高可用冗余能力&#xff0c;可利用阿里云分布式云容器平台 ACK One [ 1] 来提供统一得流量、应用和集群管理&#xff0c;实现业务流量的多集群路由和灾…

Eclipse - Switch Workspace

Eclipse - Switch Workspace References Switch Workspace References [1] Yongqiang Cheng, https://yongqiang.blog.csdn.net/

解决Ubuntu下网络适配器桥接模式下ping网址不通的情况

问题反应&#xff1a;ping不通网址 打开虚拟机中的设置&#xff0c;更改网络适配器为NAT模式 确定保存更改之后&#xff0c;退出输入如下命令。 命令1&#xff1a; sudo /etc/network/inferfaces 命令2&#xff1a; sudo /etc/init.d/network/ restart

Poller模块与Channel模块整合

目录 概要 tcp_cli.cc tcp_srv.cc server.hpp 测试结果 gdb调试 概要 本主要是将以下模块进行整合测试 Buffer缓冲区类实现(模块一)-CSDN博客 Socket套接字类实现(模块二)-CSDN博客 Channel事件管理类实现(模块三)-CSDN博客 Poller描述符监控类实现(模块四)-CSDN博客 经…

guitar pro五线谱转六线谱 guitar pro怎么去掉五线谱 简谱是什么 新手学吉他

在音乐领域&#xff0c;五线谱和六线谱是两种常见的乐谱表示方法。五线谱通常用于表示管弦乐、钢琴和其他键盘类乐器的音乐&#xff0c;而六线谱则常用于表示吉他等弦乐器的音乐。Guitar Pro软件作为一款专业的吉他编奏软件&#xff0c;六线谱的音乐更适合在软件中编奏。因此&a…

揭秘:一行代码搞定.Net API高并发的烦恼

高并发下的接口请求重复提交问题 在.Net开发中&#xff0c;我们经常遇到用户疯狂点击同一按钮&#xff0c;或者服务响应慢时重复发送请求&#xff0c;导致数据重复添加或混乱。这不仅浪费资源&#xff0c;更会得到错误的业务结果。如何高效解决这一普遍问题呢&#xff1f; 常规…

AI算法初识之分类汇总

一、背景 AI算法的分类方式多种多样&#xff0c;可以根据不同的学习机制、功能用途以及模型结构进行划分。以下是一些主要的分类方式及相应的代表性算法&#xff1a; 1. 按照学习类型 - **监督学习**&#xff1a; - 线性回归&#xff08;Linear Regression&#xff09; …

轨道交通信号增强与覆盖解决方案——经济高效,灵活应用于各类轨道交通场景!

方案背景 我国是世界上轨道交通里程最长的国家&#xff0c;轨道交通也为我们的日常出行带来极大的便利。伴随着无线通信技术的快速发展将我们带入电子时代&#xff0c;出行的过程中对无线通信的依赖程度越来越高&#xff0c;无论是车站还是车内都需要强大、高质量的解决方案以…

【NextJS】nextjs+qiankun遇ReferenceError: window is not defined

实验环境&#xff1a; qiankun: ^2.10.16next: 14.1.0react: ^18.2.0 根据官方手册快速上手教程(链接) 构建主程序实验代码&#xff1a; qiankun部分&#xff1a; // file: micro-base/plugins/qiankun/index.tsimport type { AppMetadata } from qiankun; import { registe…

vue+springboot登录与注册功能的实现

①首先写一个登录页面 <template> <div style"background-color: #42b983;display: flex;align-items: center;justify-content: center;height: 100vh"><div style"background-color: white;display: flex;width: 50%;height: 50%;overflow: h…

Camtasia Studio2024中文汉化版下载安装激活图文教程

Camtasia studio 2024是一款功能强大的屏幕录制和视频编辑软件。它可以帮助用户轻松地记录电脑屏幕上的任何操作&#xff0c;并可以将录制的视频进行编辑和制作成高质量的视频教程、演示文稿、培训课程等。 Camtasia studio 2024具有直观的界面和易于使用的工具&#xff0c;包…

软件实例分享,操作简单美发店会员登记记账本vip会员管理系统软件教程

软件实例分享&#xff0c;操作简单美发店会员登记记账本vip会员管理系统软件教程 一、前言 以下软件程序教程以 佳易王美发店会员管理系统软件V16为例说明 软件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 1、新会员可以直接使用手.机号&#xff0c;不需…

网络安全实验(三)

1.办公区设备可以通过电信和移动两条链路上网&#xff0c;且需要保留一个公网ip不能用来转换 2.分公司设备可以通过两条链路访问到dmz区域的http服务器 3.分公司内部客户端可以通过公网地址访问到内部服务器 4.FW1和FW3组成主备模式的双击热备 5.办公区上网用户限制流量不超…

曲线生成 | 图解B样条曲线生成原理(基本概念与节点生成算法)

目录 0 专栏介绍1 什么是B样条曲线&#xff1f;2 基函数的de Boor递推式3 B样条曲线基本概念图解4 节点生成公式 0 专栏介绍 &#x1f525;附C/Python/Matlab全套代码&#x1f525;课程设计、毕业设计、创新竞赛必备&#xff01;详细介绍全局规划(图搜索、采样法、智能算法等)…

Vue3+vite搭建基础架构(6)--- 使用vue-router

Vue3vite搭建基础架构&#xff08;6&#xff09;--- 使用vue-router 说明官方文档安装vue-router使用vue-router测试vue-router 说明 这里记录下自己在Vue3vite的项目使用vue-router的过程&#xff0c;不使用ts语法&#xff0c;方便以后直接使用。这里承接自己的博客Vue3vite搭…

第五次作业:LMDeploy 的量化和部署

参考文档&#xff1a;https://github.com/InternLM/tutorial/blob/main/lmdeploy/lmdeploy.md 基础作业&#xff1a; 使用 LMDeploy 以本地对话、网页Gradio、API服务中的一种方式部署 InternLM-Chat-7B 模型&#xff0c;生成 300 字的小故事&#xff08;需截图&#xff09; …

免费的一键伪原创工具哪个好用?有答案

免费的一键伪原创工具对于许多有写作需求的朋友来说是非常实用的&#xff0c;免费的一键伪原创工具不仅可以帮助大家高效率的输出所要的文章内容&#xff0c;而且关键还是免费就能使用的。对于网上比比旨是免费的一键伪原创工具中&#xff0c;我们如何挑选到那个好用的免费一键…

【目标跟踪】提供一种简单跟踪测距方法(c++)

文章目录 一、前言二、c代码2.1、Tracking2.2、KalmanTracking2.3、Hungarian2.4、TrackingInfo 三、调用示例四、结果 一、前言 在许多目标检测应用场景中&#xff0c;完完全全依赖目标检测对下游是很难做出有效判断&#xff0c;如漏检。检测后都会加入跟踪进行一些判断或者说…

Rust-知多少?

文章目录 前言1.使用下划线开头忽略未使用的变量2. 变量解构3.常量4.变量遮蔽&#xff08;shadowing&#xff09;5. 类似println!("{}", x); 为啥加感叹号6.单元类型7. -> 运算符到哪去了&#xff1f;总结 前言 Rust 学习系列&#xff0c;记录一些rust使用小技巧…