Leetcode 热题100 之 二叉树3

1.二叉树展开为链表

在这里插入图片描述
思路分析:迭代法。对于每个节点,我们将其左子树放到右子树的位置。将原来的右子树接到新的右子树(也就是原来的左子树)的末端。移动到右子节点,继续处理下一节点,直到所有节点都处理完。

  • 遍历当前节点,如果该节点有左子节点;

    • 将左子树的最右节点找到(以便连接原来的右子树);
    • 将当前节点的右子树街道左子树的最右节点;
    • 将当前节点的左子树放到右子树的位置,并将左子树置为空;
  • 移动到右子节点,重复上述过程知道所有接二点都处理完毕。

具体实现代码(详解版):

class Solution {
public:void flatten(TreeNode* root) {TreeNode* current = root;while (current) {if (current->left) {// 找到左子树的最右节点TreeNode* rightmost = current->left;while (rightmost->right) {rightmost = rightmost->right;}// 将当前节点的右子树接到左子树的最右节点rightmost->right = current->right;// 将左子树移动到右子树的位置,并将左子树置为空current->right = current->left;current->left = nullptr;}// 移动到右子节点,继续展开current = current->right;}}
};
  • 时间复杂度:O(n),其中n是二叉树的节点数
  • 空间复杂度:O(1),因为该方法是原地修改树,不需要额外的空间。

2.从前序与中序构造二叉树

在这里插入图片描述
思路分析:递归

  • 先序遍历的第一个元素是树的根节点;
  • 中序遍历中,根节点左侧的所有元素构成左子树,右侧的所有元素构成右子树;
  • 所以我们可以先从先序遍历中提取根节点,然后在中序遍历中找到该节点的位置,将数组分为左子树和右子树的部分。重复递归,分别构造左右子树。
    • inorder[0:index] 表示左子树的节点。
    • inorder[index+1:] 表示右子树的节点。

具体实现代码(详解版):

class Solution {
public:// 哈希表,用于快速定位中序遍历中根节点的位置unordered_map<int, int> inorderMap;TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {// 将中序遍历的值与索引存入哈希表,便于快速查找根节点位置for (int i = 0; i < inorder.size(); ++i) {inorderMap[inorder[i]] = i;}// 开始递归构建二叉树return buildSubTree(preorder, 0, preorder.size() - 1, 0, inorder.size() - 1);}private:// 递归构建子树TreeNode* buildSubTree(const vector<int>& preorder, int preStart, int preEnd, int inStart, int inEnd) {// 如果索引越界,返回空节点if (preStart > preEnd || inStart > inEnd) return nullptr;// 先序遍历的第一个节点是根节点int rootVal = preorder[preStart];TreeNode* root = new TreeNode(rootVal);// 在中序遍历中找到根节点的位置int inRootIndex = inorderMap[rootVal];int leftTreeSize = inRootIndex - inStart;// 构建左子树root->left = buildSubTree(preorder, preStart + 1, preStart + leftTreeSize,inStart, inRootIndex - 1);// 构建右子树root->right = buildSubTree(preorder, preStart + leftTreeSize + 1, preEnd,inRootIndex + 1, inEnd);return root;}
};
  • 时间复杂度:O(n),其中n是节点数;
  • 空间复杂度:O(n),递归栈的最大深度为树的高度,平均情况下为O(log n),最坏情况下为O(n)。

3.路径总和III

在这里插入图片描述
思路分析:DFS

  • 路径的定义:路径可以从任意节点开始,并且只能向下(即只能从父节点到子节点)。这意味着我们需要考虑每个节点作为路径的起点。
  • 递归遍历:我们需要递归遍历每个节点,记录当前路径的和,并检查是否有满足条件的路径
  • 使用哈希表:为了高效地查找满足条件的路径,我们可以使用哈希表来存储当前路径和的出现次数。当我们在某个节点上访问时,计算到该节点的路径和。如果该路径和减去 targetSum 的值已经存在于哈希表中,那么就表示存在这样的路径。
  • 处理路径和的增加与减少:在进入某个节点时增加路径和的计数,离开节点时减少路径和的计数,这样可以确保只统计以该节点为起点的路径。
  • dfs函数
    • 当节点为空时返回 0。
    • 更新当前路径和 currentSum。
    • 通过 currentSum - targetSum 在哈希表中查找满足条件的路径数,并累加到 count
    • 更新哈希表,记录当前路径和出现的次数。
    • 递归访问左子树和右子树,累加找到的路径数。
    • 回溯时,减少当前路径和的计数以防止影响其他路径的统计。

具体实现代码(详解版):

class Solution {
public:// 主函数,初始化参数并开始递归int pathSum(TreeNode* root, int targetSum) {unordered_map<long long, int> prefixSumCount; // 使用 long long 防止溢出prefixSumCount[0] = 1; // 处理从根节点到当前节点的路径和为 targetSum 的情况return dfs(root, targetSum, 0, prefixSumCount);}private:// 深度优先搜索函数int dfs(TreeNode* node, long long targetSum, long long currentSum, unordered_map<long long, int>& prefixSumCount) {if (!node) return 0; // 如果节点为空,返回 0// 更新当前路径和currentSum += node->val;int count = prefixSumCount[currentSum - targetSum]; // 找到满足条件的路径数// 更新前缀和的出现次数prefixSumCount[currentSum]++;// 递归遍历左右子树count += dfs(node->left, targetSum, currentSum, prefixSumCount);count += dfs(node->right, targetSum, currentSum, prefixSumCount);// 在回溯时,减少当前路径和的计数prefixSumCount[currentSum]--;return count; // 返回找到的路径数}
};
  • 时间复杂度:O(n),其中n是节点数;
  • 空间复杂度:O(n),主要用于哈希表的存储和递归栈的深度

4.二叉树的最近公共祖先

在这里插入图片描述要找到二叉树中两个节点的最近公共祖先(Lowest Common Ancestor, LCA),可以使用递归的深度优先搜索(DFS)方法。下面是实现的思路和代码。
思路分析

  • 递归遍历:使用DFS递归遍历树的每个节点,直到找到目标节点p或q;

  • 返回值的含义:

    • 如果当前节点为null,返回null;
    • 如果当前节点是p或q,返回该节点;
    • 如果左子树或者右子树找到了一个目标节点,则说明当前节点可能是LCA;
  • 判断LCA

    • 如果左右子树分别返回p和q,则当前节点就是LCA;
    • 如果仅有一个子树返回目标节点,说明目标节点在该子树中,继续返回;
    • 即为如果左子树和右子树都返回非空节点,当前节点就是最近公共祖先。;
    • 否则,返回非空的子树节点(如果存在的话)。

具体实现代码(详解版):

class Solution {
public:TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {// 如果根节点为空或找到 p 或 q,直接返回根节点if (root == nullptr || root == p || root == q) {return root;}// 递归查找左子树和右子树TreeNode* left = lowestCommonAncestor(root->left, p, q);TreeNode* right = lowestCommonAncestor(root->right, p, q);// 如果左子树和右子树都有找到的节点,当前节点就是 LCAif (left && right) {return root;}// 否则返回找到的子树节点return left ? left : right;}
};
  • 时间复杂度:O(n),n为节点总数;
  • 空间复杂度:O(n),用于存储前缀和

5.二叉树的最大路径和

在这里插入图片描述
思路分析:要找到二叉树中的最大路径和,可以使用深度优先搜索(DFS)的方法。这里的关键在于如何计算以每个节点为根的最大路径和,并在递归过程中更新全局最大路径和。

  • 定义:路径和是指路径中所有节点的值之和,我们需要计算每个节点的左右子树的路径和,并通过该节点形成的路径进行更新。
  • 递归函数:
    • 在每个节点上,选择将其值与其左子树和右子树的最大路径和相加,得到经过当前节点的路径和;
    • 需要保持一个全局变量来记录当前找到的最大路径和;
  • 处理路径和:
    • 对于每个节点,我们考虑两种情况:
      • 以当前节点为根的路径和(可能由左右子树的路径和相加得到);
      • 单独的左子树和右子树的路径和(仅向上返回给父节点的值)

具体实现代码(详解版):

class Solution {
public:int maxPathSum(TreeNode* root) {int maxSum = INT_MIN; // 初始化最大路径和maxGain(root, maxSum); // 调用递归函数return maxSum; // 返回结果}private:// 计算以当前节点为根的最大路径和int maxGain(TreeNode* node, int& maxSum) {if (!node) return 0; // 节点为空,返回 0// 递归计算左右子树的最大路径和,负值不贡献,取 0int leftGain = max(maxGain(node->left, maxSum), 0);int rightGain = max(maxGain(node->right, maxSum), 0);// 计算经过当前节点的路径和int currentPathSum = node->val + leftGain + rightGain;// 更新全局最大路径和maxSum = max(maxSum, currentPathSum);// 返回当前节点的最大贡献(给父节点)return node->val + max(leftGain, rightGain);}
};
  • 时间复杂度:O(n),每个节点只被访问一次;
  • 空间复杂度:O(h),h为树的高度。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

UE5.4 PCG Layered Biomes插件

B站学习链接 官方文档 一、PCGSpawn Preset&#xff1a;负责管理PCG要用到的植被资产有哪些 二、BiomesSettings&#xff1a;设置要使用的植被资产Layer、Spawn参数 1.高度Layer参数&#xff1a; 2.地形Layer&#xff1a;我这里用地形样条线绘制了一块地形Layer 绘制点和…

单个相机矫正畸变

1、通过标定助手获取到内参外参&#xff0c;外参在此无效&#xff0c;只用到了内参 2、然后通过halcon算子进行矫正 参考&#xff1a;超人视觉

Orleans8.2入门测试

微软官方文档&#xff1a;快速入门&#xff1a;使用 ASP.NET Core 生成第一个 Orleans 应用 - .NET | Microsoft Learn 项目及引入的nuget库&#xff1a; 1、接口项目&#xff1b;2、接口实现项目&#xff1b;3、silo项目&#xff1b;4、客户端项目 其中Microsoft.Orleans.St…

电赛入门之软件stm32keil+cubemx

hal库可以帮我们一键生成许多基本配置&#xff0c;就不需要自己写了&#xff0c;用多了hal库就会发现原来用基本库的时候都过的什么苦日子&#xff08;笑 下面我们以f103c8t6&#xff0c;也就是经典的最小核心板来演示 一、配置工程 首先来新建一个工程 这里我们配置rcc和sys&…

第三十章 章节练习商品列表组件封装

目录 一、需求说明 二、技术要点 三、完整代码 3.1. main.js 3.2. App.vue 3.3. MyTable.vue 3.4. MyTag.vue 一、需求说明 1. my-tag 标签组件封装 (1) 双击显示输入框&#xff0c;输入框获取焦点 (2) 失去焦点&#xff0c;隐藏输入框 (3) 回显标签信息 (4) 内…

vue 快速入门

文章目录 一、插值表达式 {{}}二、Vue 指令2.1 v-text 和 v-html&#xff1a;2.2 v-if 和 v-show&#xff1a;2.3 v-on&#xff1a;2.4 v-bind 和 v-model&#xff1a;2.5 v-for&#xff1a; 三、生命周期四、Vue 组件库 Element五、Vue 路由 本文章适用于后端人员&#xff0c;…

数据建模圣经|数据模型资源手册卷2,探索数据库逻辑模型设计

在企业信息系统体系结构中&#xff0c;数据处于核心地位。数据模型是信息系统开发和应用的基本指南&#xff0c;在逻辑模型层面为数据在数据库中的存储提供蓝图&#xff0c;以及对宏观世界的抽象设计。 简介 《The Data Model Resource Book, Revised Edition, Volume2》&#…

形态学操作篇 原理公式代码齐活

一、腐蚀 腐蚀操作的核心原理是利用一个结构元素在图像上进行扫描&#xff0c;判断结构元素所覆盖的区域与前景像素的关系。如果结构元素完全被包含在前景像素区域内&#xff0c;那么结构元素中心对应的像素位置在腐蚀后的图像中被标记为前景像素&#xff1b;如果结构元素不完…

Unity引擎材质球残留贴图引用的处理

大家好&#xff0c;我是阿赵。   这次来分享一下Unity引擎材质球残留贴图引用的处理 一、 问题 在使用Unity调整美术效果的时候&#xff0c;我们很经常会有这样的操作&#xff0c;比如&#xff1a; 1、 同一个材质球切换不同的Shader、 比如我现在有2个Shader&#xff0c;…

Flarum:简洁而强大的开源论坛软件

Flarum简介 Flarum是一款开源论坛软件&#xff0c;以其简洁、快速和易用性而闻名。它继承了esoTalk和FluxBB的优良传统&#xff0c;旨在提供一个不复杂、不臃肿的论坛体验。Flarum的核心优势在于&#xff1a; 快速、简单&#xff1a; Flarum使用PHP构建&#xff0c;易于部署&…

数据结构-图

1. 感性的认识图 图是是数据结构中最复杂的一种。图的概念特别特别的多&#xff0c;相关的算法问题也很多。如果我们一开始就讲复杂的概念&#xff0c;可能很多同学都学不下去&#xff0c;太深奥&#xff0c;太枯燥。我们不妨先感性的认识图。 图看起来就像下图这样&#xff1…

普林斯顿微积分读本PDF(英文版原版)

普林斯顿微积分读本PDF英文版: https://caiyun.139.com/m/i?005Chb93yVHtQ 对于大多数学生来说&#xff0c;微积分或许是他们曾经上过的倍感迷茫且最受挫折的一门课程了. 而《普林斯顿微积分读本》 不仅让学生能有效地学习微积分&#xff0c;更重要的是提供了战胜微积分的必备…

Netty学习——NIO基础与IO模型

导学 Socket和NIO的区别 Socket和NIO是Java中用于网络编程的两个不同的API&#xff0c;具有不同的设计理念和用途。以下是它们的主要区别&#xff1a; 1. 定义 Socket: Socket是Java中用于实现网络通信的传统API&#xff0c;通常被称为Java I/O&#xff08;输入/输出&#…

Cesium基础-(Entity)-(ellipse)

里边包含Vue、React框架代码详细步骤、以及代码详细解释 6、ellipse 圆与椭圆 EllipseGeometry(椭圆几何体)是 Cesium 中用于在三维空间中创建椭圆形状的类。这种椭圆形状可以位于地球表面(或其他椭球体)上,也可以在地球表面上方或下方的一定高度。EllipseGeometry 允许你…

014:无人机遥控器操作

摘要&#xff1a;本文详细介绍了无人机遥控器及其相关操作。首先&#xff0c;解释了油门、升降舵、方向舵和副翼的概念、功能及操作方式&#xff0c;这些是控制无人机飞行姿态的关键部件。其次&#xff0c;介绍了美国手、日本手和中国手三种不同的操作模式&#xff0c;阐述了遥…

Java—— CompletableFuture

CompletableFuture 1、概述1.1、Future接口1.2、CompletionStage接口 2、CompletableFuture结构2.1、字段和常量2.2、内部类 3、CompletableFuture原理3.1、设计思想3.2、获取任务结果的实现不带参数的Get方法实现带超时参数的Get方法实现立即返回结果的GetNow方法实现 3.3、开…

uniapp使用uni.createInnerAudioContext()播放指定音频并且切换

uniapp使用uni.createInnerAudioContext()播放指定音频并且切换 因为做的小程序或者h5需要视频讲解或者音乐组件的 默认展示播放按钮&#xff0c;当点击播放的时候 显示暂停音乐这样的一个效果。 在unipp中我们直接只用uni.createInnerAudioContext()代替audio&#xff0c;使用…

《TCP/IP网络编程》学习笔记 | Chapter 2:套接字类型与协议设置

《TCP/IP网络编程》学习笔记 | Chapter 2&#xff1a;套接字类型与协议设置 《TCP/IP网络编程》学习笔记 | Chapter 2&#xff1a;套接字类型与协议设置套接字协议及其数据传输特性协议&#xff08;Protocol&#xff09;创建套接字协议族&#xff08;Protocol Family&#xff0…

小林渗透入门:burpsuite+proxifier抓取小程序流量

目录 前提&#xff1a; 代理&#xff1a; proxifier&#xff1a; 步骤&#xff1a; bp证书安装 bp设置代理端口&#xff1a; proxifier设置规则&#xff1a; proxifier应用规则&#xff1a; 结果&#xff1a; 前提&#xff1a; 在介绍这两个工具具体实现方法之前&#xff0…

举重场景哑铃图像分割系统:全面改进提升

举重场景哑铃图像分割系统源码&#xff06;数据集分享 [yolov8-seg-GhostHGNetV2&#xff06;yolov8-seg-EfficientHead等50全套改进创新点发刊_一键训练教程_Web前端展示] 1.研究背景与意义 项目参考ILSVRC ImageNet Large Scale Visual Recognition Challenge 项目来源AA…