代码随想录笔记|C++数据结构与算法学习笔记-二叉树(四)|LeetCode222.完全二叉树的结点个数、110.平衡二叉树、257.二叉树的所有路径

本文主要是介绍代码随想录笔记|C++数据结构与算法学习笔记-二叉树(四)|LeetCode222.完全二叉树的结点个数、110.平衡二叉树、257.二叉树的所有路径,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 完全二叉树的结点个数
    • 思路
      • 普通二叉树的解法
      • 完全二叉树的思路
    • 伪代码实现
    • CPP代码实现
  • 平衡二叉树
    • 思路
      • 遍历顺序
    • 伪代码实现
    • CPP代码实现
  • 二叉树的所有路径
    • 思路和遍历顺序
    • 为什么会有回溯
    • 伪代码实现
    • CPP代码实现

完全二叉树的结点个数

力扣题目链接

文章链接:完全二叉树的结点个数

思路

普通二叉树的解法

确定遍历方法:后序遍历

  • 确定递归的返回值和参数
int getNum(node){}
  • 确定终止条件
if (node == NULL) return 0;
  • 单层递归的逻辑
leftnum = getNum(node->left);
rightnum = getNum(node->right);
result = leftNum + rightnum + 1;
return result;

精简代码后:

return getNum(left) + getNum(right) + 1;

完全二叉树的思路

本题既然叫做完全二叉树的结点个数,那么他肯定是利用二叉树的特性来总结出结点数量。

完全二叉树的定义:除了底层结点,上面的结点都是满的,底层结点是从左到右依次排开的

我们可以把完全二叉树和满二叉树结合起啦进行解题。如果是满二叉树,深度为 n n n,其结点个数就是 2 n − 1 2^n- 1 2n1

所以如果我们可以知道根结点的子树如果是个满二叉树,我们就直接用公式来计算。

那么就引出了以下关键问题:

  • 如何判断其子树是满二叉树。
  • 并且同时求它的深度呢?

如果它是满二叉树,那就说明向左遍历的深度和向右遍历的深度一定是相等的。并且,最后的叶子结点左右遍历后中间肯定存在着叶子结点,而不会是空的,这是完全二叉树为我们保证的。如果左右遍历的深度不相等,那肯定就不是满二叉树了,关于这一点可以画图确认。

这里的思路非常严谨,建议直接去看视频:要理解普通二叉树和完全二叉树的区别! | LeetCode:222.完全二叉树节点的数量

这个方法避免了我们取遍历一些中间的、没有必要去遍历的结点,因为完全二叉树为我们保证的。

伪代码实现

  • 确定返回值和参数
int getNum(node){}
  • 确定终止条件:遇到结点为空的情况;遇到子树为满二叉树的情况,我们要把子树的结点数量返回上去,所以我们遇到的子树是不是满二叉树,这个逻辑是写在终止条件里的
if(node == NULL) return 0;
left = node->left;//指向结点的左侧,左侧遍历计算左侧深度
right = node->right;//指向结点的右侧,右侧遍历计算右侧深度
leftdepth = 0; rightdepth = 0;
//左侧遍历统计左侧深度
while(left){left = left->left;leftdepth++;
}
//右侧遍历统计右侧深度
while(right){right = right->right;rightdepth++;
}
if (leftdepth == rightdepth)//左侧深度和右侧深度相等,说明是满二叉树return (2<<leftdepth) - 1;
  • 单层递归的逻辑
leftnum = getNum(node->left);//左
rightnum = getNum(node->right);//右
result = leftnum + rightnum + 1;//中
return result;

CPP代码实现

// 普通二叉树
class Solution {
private:int getNodesNum(TreeNode* cur) {if (cur == NULL) return 0;int leftNum = getNodesNum(cur->left);      // 左int rightNum = getNodesNum(cur->right);    // 右int treeNum = leftNum + rightNum + 1;      // 中return treeNum;}
public:int countNodes(TreeNode* root) {return getNodesNum(root);//精简//int countNodes(TreeNode* root) {//    if (root == NULL) return 0;//   return 1 + countNodes(root->left) + countNodes(root->right);//}}
};
//完全二叉树
class Solution {
public:int countNodes(TreeNode* root) {if (root == nullptr) return 0;TreeNode* left = root->left;TreeNode* right = root->right;int leftDepth = 0, rightDepth = 0; // 这里初始为0是有目的的,为了下面求指数方便while (left) {  // 求左子树深度left = left->left;leftDepth++;}while (right) { // 求右子树深度right = right->right;rightDepth++;}if (leftDepth == rightDepth) {return (2 << leftDepth) - 1; // 注意(2<<1) 相当于2^2,所以leftDepth初始为0}return countNodes(root->left) + countNodes(root->right) + 1;}
};

平衡二叉树

力扣题目链接

后序遍历求高度,高度判断是否平衡 | LeetCode:110.平衡二叉树

平衡二叉树:左右子树的高度差小于等于1

思路

总体的思路就是判断每一个结点的左右子树的高度,看它的高度差是否超过1.

遍历顺序

求高度的话一定要用后序遍历;求深度要用前序遍历。

伪代码实现

  • 参数和返回值
int getHeight(node)
  • 确定终止条件:如果一个结点的左右子树的高度差超过了1,说明已经不是平衡二叉树了,那么当我们发现任何一个结点的左右孩子的高度不符合我们平衡二叉树的条件,我们就不返回这个结点的高度了,而是直接返回-1。
if (node == NULL) return 0;
  • 单层递归逻辑
//左右子树不符合高度差小于1的情况
//左
leftHeight = getHeight(node->left);
if (leftHeight == -1) return -1;
//右
rightHeight = getHeight(node->right);
if(rightHeight == -1) return -1;
int result;
//中
if(abs(rightHeight - leftHeight) > 1) result = -1;
else result = 1 + max(rightHeight, leftHeight);//左右子树的最大高度+父结点本身的高度等于当前结点的最大高度
return result;

CPP代码实现

class Solution {
public:// 返回以该节点为根节点的二叉树的高度,如果不是平衡二叉树了则返回-1int getHeight(TreeNode* node) {if (node == NULL) {return 0;}int leftHeight = getHeight(node->left);if (leftHeight == -1) return -1;int rightHeight = getHeight(node->right);if (rightHeight == -1) return -1;return abs(leftHeight - rightHeight) > 1 ? -1 : 1 + max(leftHeight, rightHeight);}bool isBalanced(TreeNode* root) {return getHeight(root) == -1 ? false : true;}
};

二叉树的所有路径

思路和遍历顺序

求路径的过程中我们一般要使用前序遍历,因为只有前序遍历我们才能让父结点去指向它的孩子结点,这样才能吧我们的顺序按照题目输出出来。这里的遍历顺序肯定前序遍历。

为什么会有回溯

其实回溯的过程往往就在递归的下面。

本题我们是要收集路径,加入有一个容器从根结点出发收集路径1,那么等到收集路径2的时候我们还要弹出路径1,只剩下一个根结点在里面,这就是回溯的过程。

伪代码实现

  • 参数和返回值
void traversal(TreeNode* node, vector<int>& path, vector<string>& result){}
  • 确定终止条件
if (node->left == NULL && node->right == NULL){result.push_back(path);
}
  • 确定单层递归逻辑
//本题中,遍历中间结点的逻辑要写到前面来,因为我们的终止条件是到根结点的叶子结点就结束了,那就得return
//中
path.push_back(node->val);
if (node->left == NULL && node->right == NULL){result.push_back(path); return;
}
//左
if (node->left){traversal(node->left, path, result);path.pop_back(); 
}
//右
if (node->right){traversal(node->right, path, result);path.pop_back();
}

CPP代码实现

class Solution {
private:void traversal(TreeNode* cur, vector<int>& path, vector<string>& result) {path.push_back(cur->val); // 中,中为什么写在这里,因为最后一个节点也要加入到path中 // 这才到了叶子节点if (cur->left == NULL && cur->right == NULL) {string sPath;for (int i = 0; i < path.size() - 1; i++) {sPath += to_string(path[i]);sPath += "->";}sPath += to_string(path[path.size() - 1]);result.push_back(sPath);return;}if (cur->left) { // 左 traversal(cur->left, path, result);path.pop_back(); // 回溯}if (cur->right) { // 右traversal(cur->right, path, result);path.pop_back(); // 回溯}}public:vector<string> binaryTreePaths(TreeNode* root) {vector<string> result;vector<int> path;if (root == NULL) return result;traversal(root, path, result);return result;}
};//精简版本
class Solution {
private:void traversal(TreeNode* cur, string path, vector<string>& result) {path += to_string(cur->val); // 中if (cur->left == NULL && cur->right == NULL) {result.push_back(path);return;}if (cur->left) traversal(cur->left, path + "->", result); // 左if (cur->right) traversal(cur->right, path + "->", result); // 右}public:vector<string> binaryTreePaths(TreeNode* root) {vector<string> result;string path;if (root == NULL) return result;traversal(root, path, result);return result;}
};

这篇关于代码随想录笔记|C++数据结构与算法学习笔记-二叉树(四)|LeetCode222.完全二叉树的结点个数、110.平衡二叉树、257.二叉树的所有路径的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/865820

相关文章

python实现pdf转word和excel的示例代码

《python实现pdf转word和excel的示例代码》本文主要介绍了python实现pdf转word和excel的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价... 目录一、引言二、python编程1,PDF转Word2,PDF转Excel三、前端页面效果展示总结一

在MyBatis的XML映射文件中<trim>元素所有场景下的完整使用示例代码

《在MyBatis的XML映射文件中<trim>元素所有场景下的完整使用示例代码》在MyBatis的XML映射文件中,trim元素用于动态添加SQL语句的一部分,处理前缀、后缀及多余的逗号或连接符,示... 在MyBATis的XML映射文件中,<trim>元素用于动态地添加SQL语句的一部分,例如SET或W

C#实现获得某个枚举的所有名称

《C#实现获得某个枚举的所有名称》这篇文章主要为大家详细介绍了C#如何实现获得某个枚举的所有名称,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以参考一下... C#中获得某个枚举的所有名称using System;using System.Collections.Generic;usi

使用C#代码计算数学表达式实例

《使用C#代码计算数学表达式实例》这段文字主要讲述了如何使用C#语言来计算数学表达式,该程序通过使用Dictionary保存变量,定义了运算符优先级,并实现了EvaluateExpression方法来... 目录C#代码计算数学表达式该方法很长,因此我将分段描述下面的代码片段显示了下一步以下代码显示该方法如

C++中实现调试日志输出

《C++中实现调试日志输出》在C++编程中,调试日志对于定位问题和优化代码至关重要,本文将介绍几种常用的调试日志输出方法,并教你如何在日志中添加时间戳,希望对大家有所帮助... 目录1. 使用 #ifdef _DEBUG 宏2. 加入时间戳:精确到毫秒3.Windows 和 MFC 中的调试日志方法MFC

通过C#获取PDF中指定文本或所有文本的字体信息

《通过C#获取PDF中指定文本或所有文本的字体信息》在设计和出版行业中,字体的选择和使用对最终作品的质量有着重要影响,然而,有时我们可能会遇到包含未知字体的PDF文件,这使得我们无法准确地复制或修改文... 目录引言C# 获取PDF中指定文本的字体信息C# 获取PDF文档中用到的所有字体信息引言在设计和出

Python中的随机森林算法与实战

《Python中的随机森林算法与实战》本文详细介绍了随机森林算法,包括其原理、实现步骤、分类和回归案例,并讨论了其优点和缺点,通过面向对象编程实现了一个简单的随机森林模型,并应用于鸢尾花分类和波士顿房... 目录1、随机森林算法概述2、随机森林的原理3、实现步骤4、分类案例:使用随机森林预测鸢尾花品种4.1

python多进程实现数据共享的示例代码

《python多进程实现数据共享的示例代码》本文介绍了Python中多进程实现数据共享的方法,包括使用multiprocessing模块和manager模块这两种方法,具有一定的参考价值,感兴趣的可以... 目录背景进程、进程创建进程间通信 进程间共享数据共享list实践背景 安卓ui自动化框架,使用的是

SpringBoot生成和操作PDF的代码详解

《SpringBoot生成和操作PDF的代码详解》本文主要介绍了在SpringBoot项目下,通过代码和操作步骤,详细的介绍了如何操作PDF,希望可以帮助到准备通过JAVA操作PDF的你,项目框架用的... 目录本文简介PDF文件简介代码实现PDF操作基于PDF模板生成,并下载完全基于代码生成,并保存合并P

SpringBoot基于MyBatis-Plus实现Lambda Query查询的示例代码

《SpringBoot基于MyBatis-Plus实现LambdaQuery查询的示例代码》MyBatis-Plus是MyBatis的增强工具,简化了数据库操作,并提高了开发效率,它提供了多种查询方... 目录引言基础环境配置依赖配置(Maven)application.yml 配置表结构设计demo_st