LeetCode:二叉树的属性(13道经典题目)

2023-11-07

LeetCode:二叉树的属性(13道经典题目)

本文带来与二叉树的属性有关的经典题目,主要实现是C++。

题目 题目
101. 对称二叉树 100. 相同的树
572. 另一棵树的子树 104. 二叉树的最大深度
559. N 叉树的最大深度 111. 二叉树的最小深度
222. 完全二叉树的节点个数 110. 平衡二叉树
513. 找树左下角的值 257. 二叉树的所有路径
404. 左叶子之和 112. 路径总和
113. 路径总和 II

101. 对称二叉树

给你一个二叉树的根节点 root , 检查它是否轴对称。


对于二叉树是否对称,要比较的是根节点的左子树与右子树是不是相互翻转的,也就是说我们要比较的是两个树(这两个树是根节点的左右子树),所以在递归遍历的过程中,也是要同时遍历两棵树。

本题遍历只能是“后序遍历”,因为我们要通过递归函数的返回值来判断两个子树的内侧节点和外侧节点是否相等。正是因为要遍历两棵树而且要比较内侧和外侧节点,所以准确的来说是一个树的遍历顺序是左右中,一个树的遍历顺序是右左中。

class Solution {
public:
	bool isSymmetric(TreeNode* root) {
		if (root == nullptr) return true;
		return compare(root->left, root->right);
	}

	bool compare(TreeNode* left, TreeNode* right) {  // 后序遍历
		// 排除空节点的情况
		if (left == nullptr && right != nullptr) return false;
		else if (left != nullptr && right == nullptr) return false;
		else if (left == nullptr && right == nullptr) return true;
        // 排除了空节点,再排除数值不相同的情况
		else if (left->val != right->val) return false; 

		// 单层递归的逻辑就是处理 左右节点都不为空,且数值相同的情况
		bool outside = compare(left->left, right->right);
		bool inside = compare(left->right, right->left);
		return outside && inside;
	}
};

这里可以使用队列来比较两个树(根节点的左右子树)是否相互翻转。

class Solution {
    public:
    bool isSymmetric(TreeNode* root) {
        if (root == nullptr) return true;
        queue<TreeNode*> que;
        que.push(root->left);
        que.push(root->right);
        while (!que.empty()) {
            TreeNode* leftNode = que.front(); que.pop();
            TreeNode* rightNode = que.front(); que.pop();
            if (!leftNode && !rightNode) continue;
            if (!leftNode || !rightNode || leftNode->val != rightNode->val) {
                return false;
            }
            que.push(leftNode->left);
            que.push(rightNode->right);
            que.push(leftNode->right);
            que.push(rightNode->left);
        }
        return true;
    }
};

100. 相同的树

给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

101. 对称二叉树 基本一样。

class Solution {
public:
	bool isSameTree(TreeNode* p, TreeNode* q) {
		if (p == nullptr && q == nullptr) return true;
		else if (!p || !q || p->val != q->val) return false;
		else {
			return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
		}
	}
};
class Solution {
public:
	bool isSameTree(TreeNode* p, TreeNode* q) {
		if (p == nullptr && q == nullptr) return true;
		if (!p || !q) return false;
		queue<TreeNode*> que;
		que.push(p);
		que.push(q);
		while (!que.empty()) {
			TreeNode* left = que.front(); que.pop();
			TreeNode* right = que.front(); que.pop();
			if (!left && !right) continue;
			if (!left || !right || left->val != right->val) return false;
			que.push(left->left);
			que.push(right->left);
			que.push(left->right);
			que.push(right->right);
		}
		return true;
	}
};

572. 另一棵树的子树

给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。

一个树是另一个树的子树 则

  • 要么这两个树相等
  • 要么这个树是左树的子树
  • 要么这个树是右树的子树
class Solution {
public:
	bool isSubtree(TreeNode* root, TreeNode* subRoot) {
		if (root == nullptr && subRoot == nullptr) return true;
		if (root == nullptr && subRoot != nullptr) return false;
		return compare(root, subRoot)
			|| isSubtree(root->left, subRoot)
			|| isSubtree(root->right, subRoot);
	}

	bool compare(TreeNode* left, TreeNode* right) {
		if (!left && !right) return true;
		else if (!left || !right || left->val != right->val) return false;
		return compare(left->left, right->left) && compare(left->right, right->right);
	}
};

104. 二叉树的最大深度

给定一个二叉树,找出其最大深度。二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

使用前序求的就是深度,使用后序求的是高度。根节点的高度就是二叉树的最大深度。

class Solution {
public:
	int maxDepth(TreeNode* root) {
		return getDepth(root);
	}

	int getDepth(TreeNode* root) {
		if (root == nullptr) return 0;
		int leftDepth = getDepth(root->left);
		int rightDepth = getDepth(root->right);
		return 1 + max(leftDepth, rightDepth);
	}
};
class Solution {
public:
	int maxDepth(TreeNode* root) {
		result = 0;
		if (root == nullptr) return result;
		getDepth(root, 1);
		return result;
	}

	void getDepth(TreeNode* node, int depth) {
		result = depth > result ? depth : result; // 中
		if (node->left == nullptr && node->right == nullptr) {
			return;
		}

		if (node->left) {
			getDepth(node->left, depth + 1);
		}
		if (node->right) {
			getDepth(node->right, depth + 1);
		}
		return;
	}

	int result = 0;
};

使用迭代法的话,使用层序遍历是最为合适的,因为最大的深度就是二叉树的层数,和层序遍历的方式极其吻合。代码见:104. 二叉树的最大深度 层次遍历迭代法

559. N 叉树的最大深度

给定一个 N 叉树,找到其最大深度。最大深度是指从根节点到最远叶子节点的最长路径上的节点总数。N 叉树输入按层序遍历序列化表示,每组子节点由空值分隔。

class Solution {
public:
    int maxDepth(Node* root) {
        return getDepth(root);
    }

    int getDepth(Node* node) {
        int depth = 0;
        if (node == nullptr) return 0;
        /*for (vector<Node*>::iterator it = node->children.begin(); it != node->children.end(); it++) {
            depth = max(getDepth(*it), depth);
        }*/
        
        for (int i = 0; i < node->children.size(); i++) {
            depth = max(getDepth(node->children[i]), depth);
        }
        return depth + 1;
    }
};
class Solution {
public:
    int maxDepth(Node* root) {
        if (root == nullptr) return 0;
        queue<Node*> que;
        int depth = 0;
        que.push(root);
        while (!que.empty()) {
            int size = que.size();
            depth++;
            for (int i = 0; i < size; i++) {
                Node* node = que.front();
                que.pop();
                for (int j = 0; j < node->children.size(); j++) {
                    if (node->children[j]) {
                        que.push(node->children[j]);
                    }
                }
            }
        }
        return depth;
    }
};

111. 二叉树的最小深度

给定一个二叉树,找出其最小深度。最小深度是从根节点到最近叶子节点的最短路径上的节点数量

class Solution {
public:
    int minDepth(TreeNode* node) {
		if (node == nullptr) return 0;
		if (node->left && !node->right) { // 当一个左子树为空,右不为空,这时并不是最低点
			return 1 + minDepth(node->left);
		}
		if (!node->left && node->right) { // 当一个右子树为空,左不为空,这时并不是最低点
			return 1 + minDepth(node->right);
		}
		return 1 + min(minDepth(node->left), minDepth(node->right));
	}
};

222. 完全二叉树的节点个数

给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。

完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。

把完全二叉树当作普通二叉树来做:

class Solution {
public:
	int countNodes(TreeNode* root) {
		if (root == nullptr) return 0;
		int leftNum = countNodes(root->left);
		int rightNum = countNodes(root->right);
		return 1 + leftNum + rightNum;
	}
};

层序遍历:

class Solution {
public:
	int countNodes(TreeNode* root) {
		if (root == nullptr) return 0;
		queue<TreeNode*> que;
		que.push(root);
		int num = 0;
		while (!que.empty()) {
			int size = que.size();
			for (int i = 0; i < size; i++) {
				TreeNode* node = que.front();
				que.pop();
				num++;
				if (node->left) que.push(node->left);
				if (node->right) que.push(node->right);
			}
		}
		return num;
	}
};

题目中给了完全二叉树,那么可以用完全二叉树的性质来做题。

完全二叉树只有两种情况,情况一:就是满二叉树,情况二:最后一层叶子节点没有满

  • 对于情况一,可以直接用 2^树深度 - 1 来计算,注意这里根节点深度为1。
  • 对于情况二,分别递归左孩子,和右孩子,递归到某一深度一定会有左孩子或者右孩子为满二叉树,然后依然可以按照情况1来计算。

如果整个树不是满二叉树,就递归其左右孩子,直到遇到满二叉树为止,用公式计算这个子树(满二叉树)的节点数量。

class Solution {
public:
	int countNodes(TreeNode* root) {
		if (root == nullptr) return 0;
		TreeNode* left = root->left;
		TreeNode* right = root->right; 
		int leftHeight = 0, rightHeight = 0; // 这里初始为0是有目的的,为了下面求指数方便
		while (left) { // 求左子树深度
			left = left->left;
			leftHeight++;
		}
		while (right) { // 求右子树深度
			right = right->right;
			rightHeight++;
		}

		if (leftHeight == rightHeight) {
			return (2 << leftHeight) - 1; // 注意(2<<1) 相当于2^2,所以leftHeight初始为0
		}
		return 1 + countNodes(root->left) + countNodes(root->right);
	}
};

110. 平衡二叉树

给定一个二叉树,判断它是否是高度平衡的二叉树。

本题中,一棵高度平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。

  • 二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数。
  • 二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数。

因为求深度可以从上到下去查 所以需要前序遍历(中左右),而高度只能从下到上去查,所以只能后序遍历(左右中)

class Solution {
public:
	bool isBalanced(TreeNode* root) {
		return getDepth(root) == -1 ? false : true;
	}

	// -1表示已经不是平衡二叉树了,否则返回值是以该节点为根节点树的高度
	int getDepth(TreeNode* node) {
		if (node == nullptr) return 0;
		int leftHeight = getDepth(node->left);
		if (leftHeight == -1) return -1;
		int rightHeight = getDepth(node->right);
		if (rightHeight == -1) return -1;
		return abs(leftHeight - rightHeight) > 1 ? -1 : 1 + max(leftHeight, rightHeight);
	}
};

通过栈模拟的后序遍历找每一个节点的高度

class Solution {
public:
	bool isBalanced(TreeNode* root) {
		stack<TreeNode*> st;
		if (root == nullptr) return true;
		st.push(root);
		while (!st.empty()) {
			TreeNode* node = st.top();
			st.pop();
			if (abs(getDepth(node->left) - getDepth(node->right)) > 1) {
				return false;
			}
			if (node->right) st.push(node->right);
			if (node->left) st.push(node->left);
		}
		return true;
	}

	// cur节点的最大深度,就是cur的高度
	int getDepth(TreeNode* cur) {
		stack<TreeNode*> st;
		if (cur != nullptr) st.push(cur);
		int depth = 0;
		int result = 0;
		while (!st.empty()) {
			TreeNode* node = st.top();
			if (node != nullptr) {
				st.pop();
				st.push(node);
				st.push(nullptr);
				depth++;
				if (node->left) st.push(node->left);
				if (node->right) st.push(node->right);
			}
			else {
				st.pop();
				node = st.top();
				st.pop();
				depth--;
			}
			result = result > depth ? result : depth;
		}
		return result;
	}
};

257. 二叉树的所有路径

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

LeetCode:二叉树的属性(13道经典题目) 的相关文章

  • Cython 和类的构造函数

    我对 Cython 使用默认构造函数有疑问 我的 C 类 Node 如下 Node h class Node public Node std cerr lt lt calling no arg constructor lt lt std e
  • Python3 在 DirectX 游戏中移动鼠标

    我正在尝试构建一个在 DirectX 游戏中执行一些操作的脚本 除了移动鼠标之外 我一切都正常 是否有任何可用的模块可以移动鼠标 适用于 Windows python 3 Thanks I used pynput https pypi or
  • 如何将图像路径保存到Live Tile的WP8本地文件夹

    我正在更新我的 Windows Phone 应用程序以使用新的 WP8 文件存储 API 本地文件夹 而不是 WP7 API 隔离存储文件 旧的工作方法 这是我如何成功地将图像保存到 共享 ShellContent文件夹使用隔离存储文件方法
  • vector 超出范围后不清除内存

    我遇到了以下问题 我不确定我是否错了或者它是一个非常奇怪的错误 我填充了一个巨大的字符串数组 并希望在某个点将其清除 这是一个最小的例子 include
  • 如何将单个 char 转换为 int [重复]

    这个问题在这里已经有答案了 我有一串数字 例如 123456789 我需要提取它们中的每一个以在计算中使用它们 我当然可以通过索引访问每个字符 但是如何将其转换为 int 我研究过 atoi 但它需要一个字符串作为参数 因此 我必须将每个字
  • 为什么 Pickle 协议 4 中的 Pickle 文件是协议 3 中的两倍,而速度却没有任何提升?

    我正在测试 Python 3 4 我注意到 pickle 模块有一个新协议 因此 我对 2 个协议进行了基准测试 def test1 pickle3 open pickle3 wb for i in range 1000000 pickle
  • 在本地网络上运行 Bokeh 服务器

    我有一个简单的 Bokeh 应用程序 名为app py如下 contents of app py from bokeh client import push session from bokeh embed import server do
  • Discord.net 无法在 Linux 上运行

    我正在尝试让在 Linux VPS 上运行的 Discord net 中编码的不和谐机器人 我通过单声道运行 但我不断收到此错误 Unhandled Exception System Exception Connection lost at
  • C++ fmt 库,仅使用格式说明符格式化单个参数

    使用 C fmt 库 并给定一个裸格式说明符 有没有办法使用它来格式化单个参数 example std string str magic format 2f 1 23 current method template
  • 需要哪个版本的 Visual C++ 运行时库?

    microsoft 的最新 vcredist 2010 版 是否包含以前的版本 2008 SP1 和 2005 SP1 还是我需要安装全部 3 个版本 谢谢 你需要所有这些
  • 如何应用一个函数 n 次? [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 假设我有一个函数 它接受一个参数并返回相同类型的结果 def increment x return x 1 如何制作高阶函数repeat可以
  • 将文本叠加在图像背景上并转换为 PDF

    使用 NET 我想以编程方式创建一个 PDF 它仅包含一个背景图像 其上有两个具有不同字体和位置的标签 我已阅读过有关现有 PDF 库的信息 但不知道 如果适用 哪一个对于如此简单的任务来说最简单 有人愿意指导我吗 P D 我不想使用生成的
  • WCF:将随机数添加到 UsernameToken

    我正在尝试连接到用 Java 编写的 Web 服务 但有些东西我无法弄清楚 使用 WCF 和 customBinding 几乎一切似乎都很好 除了 SOAP 消息的一部分 因为它缺少 Nonce 和 Created 部分节点 显然我错过了一
  • Pandas 每周计算重复值

    我有一个Dataframe包含按周分组的日期和 ID df date id 2022 02 07 1 3 5 4 2022 02 14 2 1 3 2022 02 21 9 10 1 2022 05 16 我想计算每周有多少 id 与上周重
  • C - 直接从键盘缓冲区读取

    这是C语言中的一个问题 如何直接读取键盘缓冲区中的数据 我想直接访问数据并将其存储在变量中 变量应该是什么数据类型 我需要它用于我们研究所目前正在开发的操作系统 它被称为 ICS OS 我不太清楚具体细节 它在 x86 32 位机器上运行
  • Process.Start 阻塞

    我正在调用 Process Start 但它会阻止当前线程 pInfo new ProcessStartInfo C Windows notepad exe Start process mProcess new Process mProce
  • Validation.ErrorTemplate 的 Wpf 动态资源查找

    在我的 App xaml 中 我定义了一个资源Validation ErrorTemplate 这取决于动态BorderBrush资源 我打算定义独特的BorderBrush在我拥有的每个窗口以及窗口内的不同块内
  • 使用 libcurl 检查 SFTP 站点上是否存在文件

    我使用 C 和 libcurl 进行 SFTP FTPS 传输 在上传文件之前 我需要检查文件是否存在而不实际下载它 如果该文件不存在 我会遇到以下问题 set up curlhandle for the public private ke
  • 使用按位运算符相乘

    我想知道如何使用按位运算符将一系列二进制位相乘 但是 我有兴趣这样做来查找二进制值的十进制小数值 这是我正在尝试做的一个例子 假设 1010010 我想使用每个单独的位 以便将其计算为 1 2 1 0 2 2 1 2 3 0 2 4 虽然我
  • 恢复上传文件控制

    我确实阅读了以下帖子 C 暂停 恢复上传 https stackoverflow com questions 1048330 pause resume upload in c 使用 HTTP 恢复上传 https stackoverflow

随机推荐

  • 剑指 Offer 12. 矩阵中的路径

    题解 dfs 对棋盘里的每个点都dfs一遍 看是否有合适的字符串 当找到最后一个字符位置 并且最后一个字符 并且当前字符串匹配 那么为真 注意回溯之后的标记需要改成false 因为需要回溯进行查找 class Solution public
  • Hive启停脚本

    bin bash HIVE LOG DIR HIVE HOME logs if d HIVE LOG DIR then mkdir p HIVE LOG DIR fi 检查进程是否运行正常 参数 1 为进程名 参数 2 为进程端口 func
  • Spring Cloud Alibaba Sentinel 整合 nacos 进行规则持久化

    上篇文章Spring Cloud Alibaba Sentinel 初体验介绍了Sentinel 的简单使用 在使用过程中我们发现在Sentinel 控制台中配置了规则之后 随着服务的重启 配置的规则也随之消失 Sentinel 控制台控制
  • 写成生成以给定的p为参数的伯努利样本的程序,并写出由样本计算p的程序

    根据给定的参数p 编写伯努利样本的程序如下 def bernoulli sample p 定义一个变量x x 0 产生一个0 1之间的随机数 r random random 若随机数小于等于p 则x 1 if r lt p x 1 返回x
  • python判断一个字符串是不是ip地址

    文章目录 一 解决思路 二 判断代码 一 解决思路 满足什么条件的叫ip地址 1 先判断它是不是由4段数字用点号 分隔开 2 再判断每段数字的十进制是不是在0 255之间 满足以上条件就是正确的IP地址 那么解决思路就来了 1 拿到IP 先
  • 如何过掉前端Chrome的debugger反调试

    1 禁用浏览器断点 点击图中按钮 之后将不会再命中任何断点 这种方法虽然可以防止无限循环命中debugger断点 但是也存在很大的缺陷 因为对于其他代码 我们还是需要断点调试功能的 所以这个方法仅限于静态分析 2 直接使用debugger指
  • 唯品会测试工程师面试

    秋招 笔试题是后台 前端 测试同一套的题 考基础 面试 2014 09 25 一面 为什么做测试 测试遇到的最大的困难 python和java做的网站的区别 参加过什么社团活动 有没有上唯品会买过东西要你测怎么测 有哪些测试方法举例说 HR
  • 解决 深度学习docker 端口连接被对方重设

    在容器中启动 jupyter notebook 的时候 请指定 ip 为 0 0 0 0 aka 原因 docker启动的时候 我们的命令是 p 8888 8888 比如 sudo nvidia docker run it p 8888 8
  • 输入年份,判断输入的年份是否是闰年。(闰年的条件是能被 4 整除,但不能被 100 整除;或能被 400 整除。)

    public class Task 10101003 02 public static void main String args Scanner input new Scanner System in System out println
  • Charles证书-手机刷入系统信任证书

    最近面试需要 重新捡起了爬虫 在抓包的时候发现尽管按照Charles的要求去安装证书 还是会抓不到https的包 最后发现需要把用户信任证书是不够的 需要系统信任证书才行 第一步 把代理设置成Charles的代理 具体做法 Help SSL
  • 【机器学习基本理论】详解最大似然估计(MLE)、最大后验概率估计(MAP),以及贝叶斯公式的理解

    机器学习基本理论 详解最大似然估计 MLE 最大后验概率估计 MAP 以及贝叶斯公式的理解 https mp weixin qq com s 6H0gmMWvTExySMraroLVlQ 最大似然估计 Maximum likelihood
  • 使用teamviewer搭建内网服务器。

    目录 起因 下载并安装teamviewer 服务器安装ccproxy 客户端使用SwitchyOmega 起因 学习的时候 学习视频必须使用校内的网络才能连接观看 校外无法观看 所以使用teamviewer和proxy搭建一个方便访问的服务
  • 绝对定位的元素宽度自动撑开

    position absolute white space nowrap
  • java传输json数据用md5加密过程

    1 加密过程 客户端传输数据 包含两部分 一部分原始数据 一部分签名 签名就是对原始数据MD5加密后的字节序列 而原始数据就是普通的string字符串 2 服务器端呢 将收到的原始数据 进行MD5加密后得到字节序列 将这个字节序列与传输过来
  • UDP客户端程序(C语言)

    UDP客户端程序 与UDP服务器端程序配合使用 Visual Stdio 运行 UDP客户端 cpp 定义控制台应用程序的入口点 include stdafx h include
  • 使用libevent编写高并发HTTP server

    libevent库使得高并发响应HTTP Server的编写变得很容易 整个过程包括如下几部 初始化 创建HTTP Server 指定callback 进入事件循环 另外在回调函数中 可以获取客户端请求 request的HTTP Heade
  • 多线程同步之生产者---消费者模型

    额 腾讯二面的时候 被问到了这个模型 很不幸啊 不会用代码来实现 生产者消费者模型 对于多线程程序来说 不管任何编程语言 生产者和消费者模型都是最经典的 就像学习每一门编程语言一样 Hello World 都是最经典的例子 实际上 准确说应
  • Vue 在for循环中动态添加类名及style样式集合

    介绍 在vue的 for 循环中 经常会使用到动态添加类名或者样式的情况 实现给当前的选中的 div 添加不同的样式 动态添加类名 提示 所有动态添加的类名 放在表达式里都需要添加引号 进行包裹 通过 对象 的形式 使用花括号进行包裹 使用
  • 信号处理在matlab常用函数

    stem Y 将数据序列Y从x轴到数据值按照茎状形式画出 以圆圈终止 如果Y是一个矩阵 则将其每一列按照分隔方式画出 stem X Y 在X的指定点处画出数据序列Y stem filled 以实心的方式画出茎秆 stem LINESPEC
  • LeetCode:二叉树的属性(13道经典题目)

    LeetCode 二叉树的属性 13道经典题目 本文带来与二叉树的属性有关的经典题目 主要实现是C 题目 题目 101 对称二叉树 100 相同的树 572 另一棵树的子树 104 二叉树的最大深度 559 N 叉树的最大深度 111 二叉