Day72:10.15:leetcode 二叉树20道题,用时3h30min
1. 104. 二叉树的最大深度(简单)
104. 二叉树的最大深度 - 力扣(LeetCode)
思想
1.给定一个二叉树 root
,返回其最大深度。
二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。
代码
class Solution {
public:int maxDepth(TreeNode* root) {if (root == nullptr)return 0;return max(maxDepth(root->left), maxDepth(root->right)) + 1;}
};
2. 111. 二叉树的最小深度(简单)
111. 二叉树的最小深度 - 力扣(LeetCode)
思想
1.给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明:叶子节点是指没有子节点的节点。
代码
class Solution {
public:int minDepth(TreeNode* root) {if (root == nullptr)return 0;if (root->left == nullptr)return minDepth(root->right) + 1;if (root->right == nullptr)return minDepth(root->left) + 1;return min(minDepth(root->left), minDepth(root->right)) + 1;}
};
3. 965. 单值二叉树(简单)
965. 单值二叉树 - 力扣(LeetCode)
思想
1.如果二叉树每个节点都具有相同的值,那么该二叉树就是_单值_二叉树。
只有给定的树是单值二叉树时,才返回 true
;否则返回 false
。
代码
自顶向下(先判断自己,再判断左右子树)
class Solution {
public:bool isUnivalTree(TreeNode* root) {if (root == nullptr)return true;if (root->left != nullptr && root->val!=root->left->val)return false;if (root->right != nullptr && root->val!=root->right->val)return false;return isUnivalTree(root->left) && isUnivalTree(root->right); }
};
4. 100. 相同的树(简单)
100. 相同的树 - 力扣(LeetCode)
思想
1.给你两棵二叉树的根节点 p
和 q
,编写一个函数来检验这两棵树是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
代码
class Solution {
public:bool isSameTree(TreeNode* p, TreeNode* q) {if (p == nullptr || q == nullptr) // 指针比较return p == q;if (p->val != q->val) // 值比较return false;return isSameTree(p->left, q->left) &&isSameTree(p->right, q->right); // 子树比较}
};
5. 101. 对称二叉树(简单,学习递归写法)
101. 对称二叉树 - 力扣(LeetCode)
思想
1.给你一个二叉树的根节点 root
, 检查它是否轴对称。
2.在[[十五.二叉树#4. 100. 相同的树(简单)]]的基础上改写,判断轴对称就是左右两个树p,q,p和q的值是否相等,相等的话p的左子树是否等于q的右子树,p的右子树是否等于q的左子树
代码
搜索比较
class Solution {
public:void dfs2(TreeNode* cur, vector<int>& res) {if (cur == nullptr) {res.push_back(500);return;}res.push_back(cur->val);dfs2(cur->right, res);dfs2(cur->left, res);}void dfs1(TreeNode* cur, vector<int>& res) {if (cur == nullptr) {res.push_back(500);return;}res.push_back(cur->val);dfs1(cur->left, res);dfs1(cur->right, res);}bool isSymmetric(TreeNode* root) {if (root == nullptr)return true;if (root->left == nullptr || root->right == nullptr)return root->left == root->right;vector<int> resL, resR;dfs1(root->left, resL);dfs2(root->right, resR);return resL == resR;}
};
递归版本:
class Solution {
public:bool isSameTree(TreeNode* p, TreeNode* q) {if (p == nullptr || q == nullptr)return p == q;if (p->val != q->val)return false;return isSameTree(p->left, q->right) && isSameTree(p->right, q->left);}bool isSymmetric(TreeNode* root) {return isSameTree(root->left, root->right);}
};
6. 951. 翻转等价二叉树(中等)
951. 翻转等价二叉树 - 力扣(LeetCode)
思想
1.我们可以为二叉树 T 定义一个 翻转操作 ,如下所示:选择任意节点,然后交换它的左子树和右子树。
只要经过一定次数的翻转操作后,能使 X 等于 Y,我们就称二叉树 X 翻转 等价 于二叉树 Y。
这些树由根节点 root1
和 root2
给出。如果两个二叉树是否是_翻转 等价_ 的树,则返回 true
,否则返回 false
。
2.跟[[十五.二叉树#4. 100. 相同的树(简单)]]一样,只不过多了可以左子树等于右子树且右子树等于左子树
代码
class Solution {
public:bool flipEquiv(TreeNode* root1, TreeNode* root2) {if (root1 == nullptr || root2 == nullptr)return root1 == root2;if (root1->val != root2->val)return false;return (flipEquiv(root1->left, root2->left) &&flipEquiv(root1->right, root2->right) ) || (flipEquiv(root1->left, root2->right) &&flipEquiv(root1->right, root2->left) );}
};
7. 1379. 找出克隆二叉树中的相同节点(简单)
1379. 找出克隆二叉树中的相同节点 - 力扣(LeetCode)
思想
1.给你两棵二叉树,原始树 original
和克隆树 cloned
,以及一个位于原始树 original
中的目标节点 target
。
其中,克隆树 cloned
是原始树 original
的一个 副本 。
请找出在树 cloned
中,与 target
相同 的节点,并返回对该节点的引用(在 C/C++ 等有指针的语言中返回 节点指针,其他语言返回节点本身)。
**注意:**你 不能 对两棵二叉树,以及 target
节点进行更改。只能 返回对克隆树 cloned
中已有的节点的引用。
代码
class Solution {
public:TreeNode* getTargetCopy(TreeNode* original, TreeNode* cloned,TreeNode* target) {if (original == NULL)return NULL;if (original == target)return cloned;TreeNode* tmp = getTargetCopy(original->left, cloned->left, target);if (tmp != NULL)return tmp;return getTargetCopy(original->right, cloned->right, target);}
};
8. 110. 平衡二叉树(简单,学习优化)
110. 平衡二叉树 - 力扣(LeetCode)
思想
1.给定一个二叉树,判断它是否是 平衡二叉树
2.我的代码每次判断就要获取一个高度,会重复计算
3.而优化代码是在[[十五.二叉树#1. 104. 二叉树的最大深度(简单)]]的基础上改的,不满足条件的高度为-1,不断向上归
代码
class Solution {
public:int getDepth(TreeNode* cur) {if (cur == nullptr)return 0;return max(getDepth(cur->left), getDepth(cur->right)) + 1;}bool isBalanced(TreeNode* root) {if (root == nullptr)return true;int lDep = getDepth(root->left), rDep = getDepth(root->right);if (abs(lDep - rDep) > 1)return false;return isBalanced(root->left) && isBalanced(root->right);}
};
优化代码:
class Solution {
public:int getDepth(TreeNode* cur) {if (cur == nullptr)return 0;int lDep = getDepth(cur->left);if (lDep == -1)return -1;int rDep = getDepth(cur->right);if (rDep == -1 || abs(lDep - rDep) > 1)return -1;return max(lDep, rDep) + 1;}bool isBalanced(TreeNode* root) { return getDepth(root) != -1; }
};
9. 226.翻转二叉树(简单)
226. 翻转二叉树 - 力扣(LeetCode)
思想
1.给你一棵二叉树的根节点 root
,翻转这棵二叉树,并返回其根节点。
2.有返回值的函数调用时可以不将返回值赋值,直接舍弃
代码
自顶向下:
class Solution {
public:TreeNode* invertTree(TreeNode* root) {if (root == nullptr) {return nullptr;}swap(root->left, root->right); invertTree(root->left); invertTree(root->right); return root;}
};
自底向上(必须接收返回值,因为底的指针已经变了):
class Solution {
public:TreeNode* invertTree(TreeNode* root) {if (root == nullptr) {return nullptr;}auto newL = invertTree(root->left);auto newR = invertTree(root->right);root->left = newR;root->right = newL;return root;}
};
10. 617.合并二叉树(简单,学习递归返回值的利用)
617. 合并二叉树 - 力扣(LeetCode)
思想
1.给你两棵二叉树: root1
和 root2
。
想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。
返回合并后的二叉树。
注意: 合并过程必须从两个树的根节点开始。
2.此题帮助理解在归的过程中更新当前值
root1->left=mergeTrees(root1->left,root2->left);
root1->right=mergeTrees(root1->right,root2->right);
代码
class Solution {
public:TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {if(root2==nullptr){return root1;}if(root1==nullptr){return root2;}root1->val+=root2->val;root1->left=mergeTrees(root1->left,root2->left);root1->right=mergeTrees(root1->right,root2->right);return root1;}
};
11. 2331. 计算布尔二叉树的值(简单)
2331. 计算布尔二叉树的值 - 力扣(LeetCode)
思想
1.给你一棵 完整二叉树 的根,这棵树有以下特征:
- 叶子节点 要么值为
0
要么值为1
,其中0
表示False
,1
表示True
。 - 非叶子节点 要么值为
2
要么值为3
,其中2
表示逻辑或OR
,3
表示逻辑与AND
。
计算 一个节点的值方式如下: - 如果节点是个叶子节点,那么节点的 值 为它本身,即
True
或者False
。 - 否则,计算 两个孩子的节点值,然后将该节点的运算符对两个孩子值进行 运算 。
返回根节点root
的布尔运算值。
完整二叉树 是每个节点有0
个或者2
个孩子的二叉树。
叶子节点 是没有孩子的节点。
2.逻辑或和与是||,&&
,按位或和与是|,&
代码
class Solution {
public:bool evaluateTree(TreeNode* root) {if (root->left == nullptr && root->right == nullptr)return root->val;int lVal = evaluateTree(root->left), rVal = evaluateTree(root->right);if (root->val == 2)return lVal || rVal;return lVal && rVal;}
};
12. 508. 出现次数最多的子树元素和(中等)
508. 出现次数最多的子树元素和 - 力扣(LeetCode)
思想
1.给你一个二叉树的根结点 root
,请返回出现次数最多的子树元素和。如果有多个元素出现的次数相同,返回所有出现次数最多的子树元素和(不限顺序)。
一个结点的 「子树元素和」 定义为以该结点为根的二叉树上所有结点的元素之和(包括结点本身)。
2.再维护个最大次数变量,可以简化后面逻辑
代码
class Solution {
public:typedef pair<int, int> PII;map<int, int> sumToCnt;int getSum(TreeNode* cur) {if (cur == nullptr)return 0;int lSum = getSum(cur->left), rSum = getSum(cur->right);int tSum = cur->val + lSum + rSum;++sumToCnt[tSum];return tSum;}vector<int> findFrequentTreeSum(TreeNode* root) {getSum(root);vector<int> res;vector<PII> tmp;for (auto& t : sumToCnt)tmp.push_back({t.second, t.first});sort(tmp.begin(), tmp.end(), greater<>());int maxCnt = tmp[0].first;res.push_back(tmp[0].second);for (int i = 1; i < tmp.size(); ++i) {if (tmp[i].first < maxCnt)break;res.push_back(tmp[i].second);}return res;}
};
优化代码:
class Solution {
public:typedef pair<int, int> PII;map<int, int> sumToCnt;int maxCnt = 0;int getSum(TreeNode* cur) {if (cur == nullptr)return 0;int lSum = getSum(cur->left), rSum = getSum(cur->right);int tSum = cur->val + lSum + rSum;++sumToCnt[tSum];maxCnt = max(maxCnt, sumToCnt[tSum]); return tSum;}vector<int> findFrequentTreeSum(TreeNode* root) {getSum(root);vector<int> res;vector<PII> tmp;for (auto& t : sumToCnt) {if (t.second == maxCnt)res.push_back(t.first);}return res;}
};
13. 563. 二叉树的坡度(简单)
563. 二叉树的坡度 - 力扣(LeetCode)
思想
1.给你一个二叉树的根节点 root
,计算并返回 整个树 的坡度 。
一个树的 节点的坡度 定义即为,该节点左子树的节点之和和右子树节点之和的 差的绝对值 。如果没有左子树的话,左子树的节点之和为 0 ;没有右子树的话也是一样。空结点的坡度是 0 。
整个树 的坡度就是其所有节点的坡度之和。
代码
class Solution {
public:int res = 0;int getSum(TreeNode* root) {if (root == nullptr)return 0;int lSum = getSum(root->left), rSum = getSum(root->right);res += abs(lSum - rSum);return lSum + rSum + root->val;}int findTilt(TreeNode* root) {getSum(root);return res;}
};
14. 606.根据二叉树创建字符串(中等)
606. 根据二叉树创建字符串 - 力扣(LeetCode)
思想
1.给你二叉树的根节点 root
,请你采用前序遍历的方式,将二叉树转化为一个由括号和整数组成的字符串,返回构造出的字符串。
空节点使用一对空括号对 "()"
表示,转化后需要省略所有不影响字符串与原始二叉树之间的一对一映射关系的空括号对。
2.递归逻辑:根(左)(右),右不空,必有(左),右空,根据左是否空来决定有无()
代码
class Solution {
public:string tree2str(TreeNode* root) {if (root == nullptr)return "";string lStr = tree2str(root->left), rStr = tree2str(root->right);string res = to_string(root->val);if (rStr == "") {if (lStr != "")res += "(" + lStr + ")";} else {res += "(" + lStr + ")" + "(" + rStr + ")";}return res;}
};
15. 2265. 统计值等于子树平均值的节点数(中等)
2265. 统计值等于子树平均值的节点数 - 力扣(LeetCode)
思想
1.给你一棵二叉树的根节点 root
,找出并返回满足要求的节点数,要求节点的值等于其 子树 中值的 平均值 。
注意:
n
个元素的平均值可以由n
个元素 求和 然后再除以n
,并 向下舍入 到最近的整数。root
的 子树 由root
和它的所有后代组成。
代码
class Solution {
public:int res = 0;vector<int> getSumCnt(TreeNode* cur) {if (cur == nullptr)return {0, 0};vector<int> lSumCnt = getSumCnt(cur->left),rSumCnt = getSumCnt(cur->right);int tSum = lSumCnt[0] + rSumCnt[0] + cur->val;int tCnt = lSumCnt[1] + rSumCnt[1] + 1;if (tSum / tCnt == cur->val)++res;return {tSum, tCnt};}int averageOfSubtree(TreeNode* root) {getSumCnt(root);return res;}
};
16. 1026. 节点与其祖先之间的最大差值(中等)
思想
做过了,过
代码
17. 3319. 第K大的完美二叉子树的大小(中等)
3319. 第 K 大的完美二叉子树的大小 - 力扣(LeetCode)
思想
1.给你一棵 二叉树 的根节点 root
和一个整数k
。
返回第 k
大的 完美二叉子树**的大小,如果不存在则返回 -1
。
完美二叉树 是指所有叶子节点都在同一层级的树,且每个父节点恰有两个子节点。
2.因为"每个父节点恰有两个子节点",所以知道深度就知道大小,深度h,大小2^h-1
,所以优先队列记录深度,最后计算大小
代码
class Solution {
public:priority_queue<int, vector<int>, greater<int>> pq;vector<int> getSumDep(TreeNode* cur, int& k) {if (cur == nullptr)return {0, 0};vector<int> lSumDep = getSumDep(cur->left, k),rSumDep = getSumDep(cur->right, k);int lDep = lSumDep[1], rDep = rSumDep[1];if (lDep == -1 || rDep == -1 || lDep != rDep)return {0, -1};int lSum = lSumDep[0], rSum = rSumDep[0];int tSum = lSum + rSum + 1;pq.push(tSum);if (pq.size() > k)pq.pop();return {tSum, lDep + 1};}int kthLargestPerfectSubtree(TreeNode* root, int k) {getSumDep(root, k);if (pq.size() < k)return -1;return pq.top();}
};
优化:
class Solution {
public:priority_queue<int, vector<int>, greater<int>> pq;int getDep(TreeNode* cur, int& k) {if (cur == nullptr)return 0;int lDep = getDep(cur->left, k), rDep = getDep(cur->right, k);if (lDep == -1 || rDep == -1 || lDep != rDep)return -1;pq.push(lDep + 1);if (pq.size() > k)pq.pop();return lDep + 1;}int kthLargestPerfectSubtree(TreeNode* root, int k) {getDep(root, k);if (pq.size() < k)return -1;return (1 << pq.top()) - 1;}
};
18. 1339. 分裂二叉树的最大乘积(中等,取模理解)
1339. 分裂二叉树的最大乘积 - 力扣(LeetCode)
思想
1.给你一棵二叉树,它的根为 root
。请你删除 1 条边,使二叉树分裂成两棵子树,且它们子树和的乘积尽可能大。
由于答案可能会很大,请你将结果对 10^9 + 7 取模后再返回。
2.不能在max
比较时对比较数先取模,否则会让这个数比另一比较数小
代码
class Solution {
public:typedef long long ll;const int mod=1e9+7;ll sum=0;ll res=0;void dfs(TreeNode* cur){if(cur==nullptr) return;sum+=cur->val;dfs(cur->left);dfs(cur->right);}ll getSum(TreeNode* cur){if(cur==nullptr) return 0;ll lSum=getSum(cur->left),rSum=getSum(cur->right);res=max(res,lSum*(sum-lSum));res=max(res,rSum*(sum-rSum));return lSum+rSum+cur->val;}int maxProduct(TreeNode* root) {dfs(root);getSum(root);return res%mod;}
};
19. 1372. 二叉树中的最长交错路径(中等)
1372. 二叉树中的最长交错路径 - 力扣(LeetCode)
思想
做过了,过
代码
20. 1145. 二叉树着色游戏(中等,学习)
1145. 二叉树着色游戏 - 力扣(LeetCode)
思想
1.有两位极客玩家参与了一场「二叉树着色」的游戏。游戏中,给出二叉树的根节点 root
,树上总共有 n
个节点,且 n
为奇数,其中每个节点上的值从 1
到 n
各不相同。
最开始时:
- 「一号」玩家从
[1, n]
中取一个值x
(1 <= x <= n
); - 「二号」玩家也从
[1, n]
中取一个值y
(1 <= y <= n
)且y != x
。
「一号」玩家给值为x
的节点染上红色,而「二号」玩家给值为y
的节点染上蓝色。
之后两位玩家轮流进行操作,「一号」玩家先手。每一回合,玩家选择一个被他染过色的节点,将所选节点一个 未着色 的邻节点(即左右子节点、或父节点)进行染色(「一号」玩家染红色,「二号」玩家染蓝色)。
如果(且仅在此种情况下)当前玩家无法找到这样的节点来染色时,其回合就会被跳过。
若两个玩家都没有可以染色的节点时,游戏结束。着色节点最多的那位玩家获得胜利 ✌️。
现在,假设你是「二号」玩家,根据所给出的输入,假如存在一个y
值可以确保你赢得这场游戏,则返回true
;若无法获胜,就请返回false
。
2.想到用贪心思想,计算左子树,右子树,父节点子树
![[1145. 二叉树着色游戏.png]]
左子树lSum,右子树rSum,父节点子树n-1-lSum-rSum,哪棵子树最大,二号玩家选哪棵,得到maxSum,让maxSum>n-maxSum
代码
class Solution {
public:int lSum = 0, rSum = 0;int getSum(TreeNode* cur, int x) {if (cur == nullptr)return 0;int tmpLSUm = getSum(cur->left, x), tmpRSUm = getSum(cur->right, x);if (cur->val == x) {lSum = tmpLSUm;rSum = tmpRSUm;}return tmpLSUm + tmpRSUm + 1;}bool btreeGameWinningMove(TreeNode* root, int n, int x) {getSum(root, x);int maxSum = max({lSum, rSum, n - 1 - lSum - rSum});// maxSum>n-maxSumreturn maxSum > n - maxSum;}
};