【Leetcode刷题记录_C++】【树】

树的递归

104. 二叉树的最大深度

给定一个二叉树,找出其最大深度。

二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

说明: 叶子节点是指没有子节点的节点。
思路:
DFS递归回溯

int maxDepth(TreeNode* root) {
	return root? 1 + max(maxDepth(root->left), maxDepth(root->right)): 0;
}

代码:

110. 平衡二叉树

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

本题中,一棵高度平衡二叉树定义为:

一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。

思路:
解法类似于求树的最大深度,但有两个不同的地方:一是我们需要先处理子树的深度再进行比较,二是如果我们在处理子树时发现其已经不平衡了,则可以返回一个-1,使得所有其长辈节点可以避免多余的判断
代码:

543. 二叉树的直径

给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。
思路:
递归,左右子树深度相加
代码:

437. 路径总和 III

给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目。

路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。

思路:
560. 和为 K 的子数组 类似
代码:

101. 对称二叉树

给定一个二叉树,检查它是否是镜像对称的。

例如,二叉树 [1,2,2,3,4,4,3] 是对称的。
思路:
将判断两个子树是否相等或对称类型的题的解法叫做“四步法”:
(1)如果两个子树都为空指针,则它们相等或对称
(2)如果两个子树只有一个为空指针,则它们不相等或不对称
(3)如果两个子树根节点的值不相等,则它们不相等或不对称
(4)根据相等或对称要求,进行递归处理。
每次输入两个节点进行四步判断,然后再递归判断他们的外子树和内子树
代码:

1110. 删点成林

给出二叉树的根节点 root,树上每个节点都有一个不同的值。

如果节点值在 to_delete 中出现,我们就把该节点从树上删去,最后得到一个森林(一些不相交的树构成的集合)。

返回森林中的每棵树。你可以按任意顺序组织答案。

思路:
递归,如果是删除节点,子树加入forest,返回上一层删除该节点
代码:

层次遍历

我们可以使用广度优先搜索进行层次遍历。注意,不需要使用两个队列来分别存储当前层的节点和下一层的节点,因为在开始遍历一层的节点时,当前队列中的节点数就是当前层的节点数,只要控制遍历这么多节点数,就能保证这次遍历的都是当前层的节点。

637. 二叉树的层平均值

给定一个非空二叉树, 返回一个由每层节点平均值组成的数组。
思路:
BFS
代码:

前中后序遍历

105. 从前序与中序遍历序列构造二叉树

给定一棵树的前序遍历 preorder 与中序遍历 inorder。请构造二叉树并返回其根节点。
思路:
分治,只要我们在中序遍历中定位到根节点,那么我们就可以分别知道左子树和右子树中的节点数目
代码:

144. 二叉树的前序遍历

给你二叉树的根节点 root ,返回它节点值的 前序 遍历。
思路:
①递归

void preorder(TreeNode* root) {
	visit(root);
	preorder(root->left);
	preorder(root->right);
}

②非递归

代码:

二叉查找树

特殊的二叉树:对于每个父节点,其左子节点的值小于等于父结点的值,其右子节点的值大于等于父结点的值(右子树的数大于等于根,左同理)。因此对于一个二叉查找树,我们可以在 O(n log n) 的时间内查找一个值是否存在:从根节点开始,若当前节点的值大于查找值则向左下走,若当前节点的值小于查找值则向右下走。同时因为二叉查找树是有序的,对其中序遍历的结果即为排好序的数组。

99. 恢复二叉搜索树

给你二叉搜索树的根节点 root ,该树中的两个节点被错误地交换。请在不改变其结构的情况下,恢复这棵树。

进阶:使用 O(n) 空间复杂度的解法很容易实现。你能想出一个只使用常数空间的解决方案吗?
思路:
①中序遍历
如果有两个,我们记为 i 和 j(i<j 且 ai>ai+1 && aj>aj+1 ​),那么对应被错误交换的节点即为 ai对应的节点和 aj+1 对应的节点,我们分别记为 x 和 y。

代码:

669. 修剪二叉搜索树

给你二叉搜索树的根节点 root ,同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树,使得所有节点的值在[low, high]中。修剪树不应该改变保留在树中的元素的相对结构(即,如果没有被移除,原有的父代子代关系都应当保留)。 可以证明,存在唯一的答案。

所以结果应当返回修剪好的二叉搜索树的新的根节点。注意,根节点可能会根据给定的边界发生改变。
思路:
利用递归,对它的子树进行递归,返回子树根节点,如果找到超出边界的节点,根据大小抛弃掉该节点的左/右子树,然后对另一边子树继续递归搜索
代码:

TreeNode* trimBST(TreeNode* root, int L, int R) {
	if (!root) 
		return root;
	if (root->val > R) 
		return trimBST(root->left, L, R);
	if (root->val < L) 
		return trimBST(root->right, L, R);
	root->left = trimBST(root->left, L, R);
	root->right = trimBST(root->right, L, R);
	return root;
}

字典树

用于判断字符串是否存在或者是否具有某种字符串前缀。
假如我们有一个储存了近万个单词的字典,即使我们使用哈希,在其中搜索一个单词的实际开销也是非常大的,且无法轻易支持搜索单词前缀。然而由于一个英文单词的长度 n 通常在 10 以内,如果我们使用字典树,则可以在 O(n)——近似 O(1)的时间内完成搜索,且额外开销非常小。
在这里插入图片描述

208. 实现 Trie (前缀树)

Trie(发音类似 “try”)或者说 前缀树 是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景,例如自动补完和拼写检查。

请你实现 Trie 类:

Trie() 初始化前缀树对象。
void insert(String word) 向前缀树中插入字符串 word 。
boolean search(String word) 如果字符串 word 在前缀树中,返回 true(即,在检索之前已经插入);否则,返回 false 。
boolean startsWith(String prefix) 如果之前已经插入的字符串 word 的前缀之一为 prefix ,返回 true ;否则,返回 false 。

思路:
子节点:指针数组[26]
代码:

练习

226. 翻转二叉树

左右翻转一棵二叉树。
思路:
递归,左右子树互换
代码:

617. 合并二叉树

给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。

你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。
思路:
树1上直接修改,DFS,遇到树2空枝,返回,遇到树1空枝而树2非空,复制到树1
代码:

572. 另一棵树的子树

给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。

二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。
思路:
DFS,遇到相同根节点,开始用辅函数判断
代码:

404. 左叶子之和

计算给定二叉树的所有左叶子之和。
思路:
遍历,两个辅函数,左节点函数返回NULL,加上它的值
代码:

513. 找树左下角的值

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

假设二叉树中至少有一个节点。
思路:
BFS,最后一层第一个出栈的就是
代码:

538. 把二叉搜索树转换为累加树

给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。

提醒一下,二叉搜索树满足下列约束条件:

节点的左子树仅包含键 小于 节点键的节点。
节点的右子树仅包含键 大于 节点键的节点。
左右子树也必须是二叉搜索树。

思路:
右根左遍历,前缀和
代码:

235. 二叉搜索树的最近公共祖先

给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

思路:
因为是二叉搜索树,从根节点出发搜索,第一个处于两数中间的数即为所求
代码:

530. 二叉搜索树的最小绝对差

给你一棵所有节点为非负值的二叉搜索树,请你计算树中任意两节点的差的绝对值的最小值。
思路:
中序遍历
代码:

889. 根据前序和后序遍历构造二叉树

返回与给定的前序和后序遍历匹配的任何二叉树。

pre 和 post 遍历中的值是不同的正整数。
思路:
分治,每次找到左右分支的大小(通过倒序遍历post找到右分支的根,即pre中的左右分支分界)
代码:

106. 从中序与后序遍历序列构造二叉树

根据一棵树的中序遍历与后序遍历构造二叉树。

注意:
你可以假设树中没有重复的元素。
思路:
分治,类似105
代码:

94. 二叉树的中序遍历

给定一个二叉树的根节点 root ,返回它的 中序 遍历。
思路:
不赘述
代码:

145. 二叉树的后序遍历

给定一个二叉树,返回它的 后序 遍历。
思路:
不赘述
代码:

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

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

思路:
并查集
代码:

109. 有序链表转换二叉搜索树

给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树。

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

思路:
快慢指针找中点,分治,接下来的根为该区间中点
代码:

897. 递增顺序搜索树

给你一棵二叉搜索树,请你 按中序遍历 将其重新排列为一棵递增顺序搜索树,使树中最左边的节点成为树的根节点,并且每个节点没有左子节点,只有一个右子节点。
思路:
中序遍历,第一个节点做根,后面的节点都作为上一个的右子树
代码:

653. 两数之和 IV - 输入 BST

给定一个二叉搜索树 root 和一个目标结果 k,如果 BST 中存在两个元素且它们的和等于给定的目标结果,则返回 true。
思路:
①中序转数组,双指针
②进阶:对每个遍历到的节点a,记录在一个哈希表内,每次查询hash[k-a]是否存在,存在就返回,否则继续,这样只用遍历一次
代码:

450. 删除二叉搜索树中的节点

给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。

一般来说,删除节点可分为两个步骤:

首先找到需要删除的节点;
如果找到了,删除它。

说明: 要求算法时间复杂度为 O(h),h 为树的高度

思路:
根据搜索二叉树性质,删除节点用它的的左子树根节点替换,右子树放在替换的左子树的最右节点的右子树处
代码:

引用中的代码片段是一个递归函数,名为beautifulArray,它接受一个整数n作为参数,并返回一个vector<int>类型的结果。这个函数用于生成一个长度为n的漂亮数组,漂亮数组满足以下条件:如果将其划分为两个任意长度的子数组,那么两个子数组的元素之和不相等。 函数的实现思路是通过递归,将问题划分为两个子问题,然后合并子问题的解。首先判断n是否等于1,如果等于1,则直接返回一个包含1的数组。否则,将n减1后的一半传入递归函数beautifulArray,得到一个漂亮数组res1。然后将n的一半传入递归函数beautifulArray,得到另一个漂亮数组res2。最后,将res1中的每个元素乘以2并减去1,然后与res2中的每个元素乘以2合并到结果数组res中。 引用中的代码片段是一个函数,名为translateNum,它接受一个整数num作为参数,并返回一个整数。这个函数用于计算将整数num翻译成字符串的不同方法数。 函数的实现思路是将整数num转换为字符串str,然后创建一个长度为str.size()-1的动态数组dp,用于记录不同位置的翻译方法数。然后初始化dp和dp[1]为1,表示前两位数字的翻译方法数。接下来,从第三位数字开始遍历字符串str,如果当前数字与前两位数字可以构成一个在10到25之间的整数,则将dp[i]的值设置为dp[i-1]+dp[i-2],表示当前位置的翻译方法数为前一位和前两位数字的翻译方法数之和。最后,返回dp最后一个元素的值,即为翻译整数num的不同方法数。 引用中的代码片段是一个函数,名为numberOfArithmeticSlices,它接受一个vector<int>类型的数组nums作为参数,并返回一个整数。这个函数用于计算数组nums中等差子序列的个数。 函数的实现思路是通过动态规划,创建一个与nums长度相同的动态数组dp,用于记录以每个位置为结尾的等差子序列的个数。然后遍历数组nums,从第三个元素开始,判断当前元素与前两个元素是否构成等差数列,如果是,则将dp[i]的值设置为dp[i-1]加1,表示以当前位置为结尾的等差子序列个数为前一位的等差子序列个数加1。最后,返回dp数组中所有元素的和,即为等差子序列的个数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ycr的帐号

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值