当前位置: 首页 > news >正文

每日算法刷题Day77:10.22:leetcode 二叉树bfs18道题,用时3h

十三、二叉树 BFS

1.套路

1.每轮队列弹出弹出这一层的(写代码遍历时i必须从大到小,因为队列大小在变化,遍历终止条件得是常数0)

class Solution {
public:vector<vector<int>> zigzagLevelOrder(TreeNode* root) {if (root == nullptr) // 根节点为空单独判断return {};vector<vector<int>> res;queue<TreeNode*> que;que.push(root);int dep=0; // 深度while (!que.empty()) {// 弹出这一层vector<int> tmp;// int len=que.size(); // 大小得提前记录for (int i = que.size()-1; i >=0; --i) {TreeNode* cur = que.front();que.pop();tmp.push_back(cur->val);if (cur->left)que.push(cur->left);if (cur->right)que.push(cur->right);}res.push_back(tmp);++dep;}return res;}
};

2.另一种遍历方式(记录下一层节点,然后数组指针移动(队列用数组实现))(方便遍历父节点,处理子节点,处理堂兄弟问题,也可以两次遍历):

vector<TreeNode*> que={root}; // 改成数组实现
while (!que.empty()) {// 记录下一层节点vector<TreeNode*> nxt;for(auto node:que){if(node->left) nxt.push_back(node->left);if(node->right) nxt.push_back(node->right);}que=move(nxt); // 精髓
}
2.题目描述
3.学习经验
1. 102. 二叉树的层序遍历(中等)

102. 二叉树的层序遍历 - 力扣(LeetCode)

思想

1.给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。

代码
class Solution {
public:typedef pair<TreeNode*, int> PTI;vector<vector<int>> levelOrder(TreeNode* root) {if (root == nullptr)return {};vector<vector<int>> res;queue<PTI> que;que.push({root, 0});while (!que.empty()) {auto x = que.front();que.pop();TreeNode* cur = x.first;int dep = x.second;if (res.empty() || res.size() - 1 < dep) {res.push_back({cur->val});} else {res[dep].push_back(cur->val);}if (cur->left)que.push({cur->left, dep + 1});if (cur->right)que.push({cur->right, dep + 1});}return res;}
};
2. 103.二叉树的锯齿层序遍历(中等)

103. 二叉树的锯齿形层序遍历 - 力扣(LeetCode)

思想

1.给你二叉树的根节点 root ,返回其节点值的 锯齿形层序遍历 。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。

代码
class Solution {
public:vector<vector<int>> zigzagLevelOrder(TreeNode* root) {if (root == nullptr)return {};vector<vector<int>> res;queue<TreeNode*> que;que.push(root);int isL = 0;while (!que.empty()) {// 这一层全遍历vector<int> tmp;for (int i = que.size() - 1; i >= 0; --i) {TreeNode* cur = que.front();que.pop();tmp.push_back(cur->val);if (cur->left)que.push(cur->left);if (cur->right)que.push(cur->right);}if (isL)reverse(tmp.begin(), tmp.end());res.push_back(tmp);isL ^= 1;}return res;}
};
3. 107. 二叉树的层序遍历II(中等)

107. 二叉树的层序遍历 II - 力扣(LeetCode)

思想

1.给你二叉树的根节点 root ,返回其节点值 自底向上的层序遍历 。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)

代码
class Solution {
public:vector<vector<int>> levelOrderBottom(TreeNode* root) {if (root == nullptr)return {};vector<vector<int>> res;queue<TreeNode*> que;que.push(root);while (!que.empty()) {vector<int> tmp;for (int i = que.size() - 1; i >= 0; --i) {TreeNode* cur = que.front();que.pop();tmp.push_back(cur->val);if (cur->left)que.push(cur->left);if (cur->right)que.push(cur->right);}res.push_back(tmp);}reverse(res.begin(), res.end());return res;}
};
4. 199. 二叉树的右视图(中等)

199. 二叉树的右视图 - 力扣(LeetCode)

思想

1.给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。

代码
class Solution {
public:vector<int> rightSideView(TreeNode* root) {if (root == nullptr)return {};vector<int> res;queue<TreeNode*> que;que.push(root);while (!que.empty()) {for (int i = que.size() - 1; i >= 0; --i) {TreeNode* cur = que.front();que.pop();if (i == 0)res.push_back(cur->val);if (cur->left)que.push(cur->left);if (cur->right)que.push(cur->right);}}return res;}
};
5. 513. 找树左下角的值(中等)

513. 找树左下角的值 - 力扣(LeetCode)

思想

1.给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。
假设二叉树中至少有一个节点。

代码
class Solution {
public:int findBottomLeftValue(TreeNode* root) {int res;queue<TreeNode*> que;que.push(root);while (!que.empty()) {int tmp = que.size() - 1;for (int i = que.size() - 1; i >= 0; --i) {TreeNode* cur = que.front();que.pop();if (i == tmp)res = cur->val;if (cur->left)que.push(cur->left);if (cur->right)que.push(cur->right);}}return res;}
};
6. 515. 在每个树行中找最大值(中等)

515. 在每个树行中找最大值 - 力扣(LeetCode)

思想

1.给定一棵二叉树的根节点 root ,请找出该二叉树中每一层的最大值。

代码
class Solution {
public:vector<int> largestValues(TreeNode* root) {if (root == nullptr)return {};vector<int> res;queue<TreeNode*> que;que.push(root);while (!que.empty()) {int maxn = INT_MIN;for (int i = que.size() - 1; i >= 0; --i) {TreeNode* cur = que.front();que.pop();maxn = max(maxn, cur->val);if (cur->left)que.push(cur->left);if (cur->right)que.push(cur->right);}res.push_back(maxn);}return res;}
};
7. 637.二叉树的层平均值(简单)

637. 二叉树的层平均值 - 力扣(LeetCode)

思想

1.定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值。与实际答案相差 10-5 以内的答案可以被接受。

代码
class Solution {
public:typedef long long ll;vector<double> averageOfLevels(TreeNode* root) {if (root == nullptr) return {};vector<double> res;queue<TreeNode*> que;que.push(root);while (!que.empty()) {ll sum=0;int len=que.size();for (int i = que.size()-1; i >=0; --i) {TreeNode* cur = que.front();que.pop();sum+=cur->val;if (cur->left)que.push(cur->left);if (cur->right)que.push(cur->right);}res.push_back(1.0*sum/len);}return res;}
};
8. 1161.最大层内元素和(中等)

1161. 最大层内元素和 - 力扣(LeetCode)

思想

1.给你一个二叉树的根节点 root。设根节点位于二叉树的第 1 层,而根节点的子节点位于第 2 层,依此类推。
请返回层内元素之和 最大 的那几层(可能只有一层)的层号,并返回其中 最小 的那个。

代码
class Solution {
public:typedef long long ll;int maxLevelSum(TreeNode* root) {int res;queue<TreeNode*> que;que.push(root);ll maxn = LLONG_MIN;int dep = 0;while (!que.empty()) {// 弹出这一层ll sum = 0;++dep;for (int i = que.size() - 1; i >= 0; --i) {TreeNode* cur = que.front();que.pop();sum += cur->val;if (cur->left)que.push(cur->left);if (cur->right)que.push(cur->right);}if (sum > maxn) {maxn = sum;res = dep;}}return res;}
};
9. 993.二叉树的堂兄弟节点(简单)

993. 二叉树的堂兄弟节点 - 力扣(LeetCode)

思想

1.在二叉树中,根节点位于深度 0 处,每个深度为 k 的节点的子节点位于深度 k+1 处。
如果二叉树的两个节点深度相同,但 父节点不同 ,则它们是一对堂兄弟节点。
我们给出了具有唯一值的二叉树的根节点 root ,以及树中两个不同节点的值 x 和 y 。
只有与值 x 和 y 对应的节点是堂兄弟节点时,才返回 true 。否则,返回 false

代码
class Solution {
public:typedef pair<TreeNode*, int> PTI;bool isCousins(TreeNode* root, int x, int y) {queue<PTI> que;que.push({root, -1});while (!que.empty()) {bool isX = false, isY = false;int faX = -1, faY = -1;for (int i = que.size() - 1; i >= 0; --i) {auto tmp = que.front();que.pop();TreeNode* cur = tmp.first;int fa = tmp.second;if (cur->val == x) {isX = true;faX = fa;} else if (cur->val == y) {isY = true;faY = fa;}if (cur->left)que.push({cur->left, cur->val});if (cur->right)que.push({cur->right, cur->val});}if ((isX && !isY) || (!isX && isY))return false;if (isX && isY) {return faX != faY;}}return false;}
};
10. 2583.二叉树中的第K大层和(中等)

2583. 二叉树中的第 K 大层和 - 力扣(LeetCode)

思想

1.给你一棵二叉树的根节点 root 和一个正整数 k 。
树中的 层和 是指 同一层 上节点值的总和。
返回树中第 k 大的层和(不一定不同)。如果树少于 k 层,则返回 -1 。
注意,如果两个节点与根节点的距离相同,则认为它们在同一层。
2.top-k问题

代码
class Solution {
public:typedef long long ll;long long kthLargestLevelSum(TreeNode* root, int k) {ll res;queue<TreeNode*> que;que.push(root);priority_queue<ll, vector<ll>, greater<ll>> pq;while (!que.empty()) {// 弹出这一层ll sum = 0;for (int i = que.size() - 1; i >= 0; --i) {TreeNode* cur = que.front();que.pop();sum += cur->val;if (cur->left)que.push(cur->left);if (cur->right)que.push(cur->right);}pq.push(sum);if (pq.size() > k)pq.pop();}if (pq.size() < k)return -1;return pq.top();}
};
11. 1302.层数最深叶子节点的和(中等)

1302. 层数最深叶子节点的和 - 力扣(LeetCode)

思想

1.给你一棵二叉树的根节点 root ,请你返回 层数最深的叶子节点的和 。

代码
class Solution {
public:int deepestLeavesSum(TreeNode* root) {if (root == nullptr) // 根节点为空单独判断return {};int res;queue<TreeNode*> que;que.push(root);while (!que.empty()) {// 弹出这一层int sum = 0;for (int i = que.size() - 1; i >= 0; --i) {TreeNode* cur = que.front();que.pop();sum += cur->val;if (cur->left)que.push(cur->left);if (cur->right)que.push(cur->right);}res = sum;}return res;}
};
12. 2415.反转二叉树的奇数层(中等)

2415. 反转二叉树的奇数层 - 力扣(LeetCode)

思想

1.给你一棵 完美 二叉树的根节点 root ,请你反转这棵树中每个 奇数 层的节点值。

  • 例如,假设第 3 层的节点值是 [2,1,3,4,7,11,29,18] ,那么反转后它应该变成 [18,29,11,7,4,3,1,2] 。
    反转后,返回树的根节点。
    完美 二叉树需满足:二叉树的所有父节点都有两个子节点,且所有叶子节点都在同一层。
    节点的 层数 等于该节点到根节点之间的边数。
代码
class Solution {
public:TreeNode* reverseOddLevels(TreeNode* root) {if (root == nullptr) // 根节点为空单独判断return nullptr;queue<TreeNode*> que;que.push(root);int dep = 0;while (!que.empty()) {vector<TreeNode*> nodes;vector<int> vals;for (int i = que.size() - 1; i >= 0; --i) {TreeNode* cur = que.front();que.pop();nodes.push_back(cur);vals.push_back(cur->val);if (cur->left)que.push(cur->left);if (cur->right)que.push(cur->right);}if (dep % 2) {reverse(vals.begin(), vals.end());for (int j = 0; j < nodes.size(); ++j) {nodes[j]->val = vals[j];}}++dep;}return root;}
};
13. 1609.奇偶树(中等)

1609. 奇偶树 - 力扣(LeetCode)

思想

1.如果一棵二叉树满足下述几个条件,则可以称为 奇偶树 :

  • 二叉树根节点所在层下标为 0 ,根的子节点所在层下标为 1 ,根的孙节点所在层下标为 2 ,依此类推。
  • 偶数下标 层上的所有节点的值都是  整数,从左到右按顺序 严格递增
  • 奇数下标 层上的所有节点的值都是  整数,从左到右按顺序 严格递减
    给你二叉树的根节点,如果二叉树为 奇偶树 ,则返回 true ,否则返回 false 。
代码
class Solution {
public:bool isEvenOddTree(TreeNode* root) {queue<TreeNode*> que;que.push(root);int dep = 0;while (!que.empty()) {// 弹出这一层int x;if (dep % 2)x = INT_MAX;elsex = INT_MIN;for (int i = que.size() - 1; i >= 0; --i) {TreeNode* cur = que.front();que.pop();if (dep % 2) {if (cur->val % 2 != 0 || cur->val >= x)return false;} else {if (cur->val % 2 != 1 || cur->val <= x)return false;}x = cur->val;if (cur->left)que.push(cur->left);if (cur->right)que.push(cur->right);}++dep;}return true;}
};
14. 623. 在二叉树中增加一行(中等)

623. 在二叉树中增加一行 - 力扣(LeetCode)

思想

1.给定一个二叉树的根 root 和两个整数 val 和 depth ,在给定的深度 depth 处添加一个值为 val 的节点行。
注意,根节点 root 位于深度 1 。
加法规则如下:

  • 给定整数 depth,对于深度为 depth - 1 的每个非空树节点 cur ,创建两个值为 val 的树节点作为 cur 的左子树根和右子树根。
  • cur 原来的左子树应该是新的左子树根的左子树。
  • cur 原来的右子树应该是新的右子树根的右子树。
  • 如果 depth == 1 意味着 depth - 1 根本没有深度,那么创建一个树节点,值 val 作为整个原始树的新根,而原始树就是新根的左子树。
代码
class Solution {
public:TreeNode* addOneRow(TreeNode* root, int val, int depth) {if (depth == 1)return new TreeNode(val, root, nullptr);queue<TreeNode*> que;que.push(root);int dep = 1; // 深度while (!que.empty()) {for (int i = que.size() - 1; i >= 0; --i) {TreeNode* cur = que.front();que.pop();if (dep == depth - 1) {cur->left = new TreeNode(val, cur->left, nullptr);cur->right = new TreeNode(val, nullptr, cur->right);} else {if (cur->left)que.push(cur->left);if (cur->right)que.push(cur->right);}}++dep;}return root;}
};
15. 2471.逐层排序二叉树所需的最少操作数目(中等)

2471. 逐层排序二叉树所需的最少操作数目 - 力扣(LeetCode)

思想

1.给你一个 值互不相同 的二叉树的根节点 root 。
在一步操作中,你可以选择 同一层 上任意两个节点,交换这两个节点的值。
返回每一层按 严格递增顺序 排序所需的最少操作数目。
节点的 层数 是该节点和根节点之间的路径的边数。
2.本质是[[十三.图论算法-并查集和最小生成树#5. 3551. 数位和排序需要的最小交换次数(中等,学习,技巧结论)]]的置换环问题,可以用并查集做,也可以用vis数组实现

代码

并查集:

class Solution {
public:int cnt;vector<int> fa;int find(int x) {if (fa[x] != x)fa[x] = find(fa[x]);return fa[x];}void merge(int from, int to) {int x = find(from), y = find(to);if (x == y)return;fa[x] = y;--cnt;}int minimumOperations(TreeNode* root) {int res = 0;queue<TreeNode*> que;que.push(root);while (!que.empty()) {map<int, int> valToId;int id = 0;vector<int> tmp;for (int i = que.size() - 1; i >= 0; --i) {TreeNode* cur = que.front();que.pop();valToId[cur->val] = id++;tmp.push_back(cur->val);if (cur->left)que.push(cur->left);if (cur->right)que.push(cur->right);}sort(tmp.begin(), tmp.end());int n = tmp.size();cnt = n;fa.clear();fa.resize(cnt);for (int i = 0; i < n; ++i)fa[i] = i;for (int i = 0; i < n; ++i) {int j = valToId[tmp[i]];merge(i, j);}res += n - cnt;}return res;}
};

vis数组:

sort(tmp.begin(), tmp.end());
int n = tmp.size();
map<int, int> idToId;
for (int i = 0; i < n; ++i) {int j = valToId[tmp[i]];idToId[i] = j; // 下标映射,构建环
}
res += n;
vector<bool> vis(n, false);
for (int i = 0; i < n; ++i) {if (vis[i])continue;// 显式走环while (!vis[i]) {vis[i] = true;i = idToId[i]; // 走到下一个}res -= 1; // 减去一个环
}
16. 2641. 二叉树的堂兄弟节点II(中等,xuex)

2641. 二叉树的堂兄弟节点 II - 力扣(LeetCode)

思想

1.给你一棵二叉树的根 root ,请你将每个节点的值替换成该节点的所有 堂兄弟节点值的和 。
如果两个节点在树中有相同的深度且它们的父节点不同,那么它们互为 堂兄弟 。
请你返回修改值之后,树的根 root 。
注意,一个节点的深度指的是从树根节点到这个节点经过的边数。
2.一次遍历要map记录父节点与子节点关系,会错误,应该两次遍历,第一次记录孩子那一层总和,第二次遍历记录孩子总和并赋值

代码

一次遍历:

class Solution {
public:typedef long long ll;typedef pair<TreeNode*, int> PTI;TreeNode* replaceValueInTree(TreeNode* root) {queue<PTI> que;que.push({root, -1});while (!que.empty()) {// 弹出这一层ll sum = 0;set<int> fas;map<int, vector<TreeNode*>> faToChis;map<int, ll> faToSums;for (int i = que.size() - 1; i >= 0; --i) {auto x = que.front();que.pop();TreeNode* cur = x.first;int fa = x.second;sum += cur->val;faToChis[fa].push_back(cur);faToSums[fa] += cur->val;fas.insert(fa);if (cur->left)que.push({cur->left, cur->val});if (cur->right)que.push({cur->right, cur->val});}for (auto& fa : fas) {auto chis = faToChis[fa];ll chiSum = faToSums[fa];ll newVal = sum - chiSum;for (auto& cur : chis) {cur->val = newVal;}}}return root;}
};

两次遍历:

class Solution {
public:typedef long long ll;TreeNode* replaceValueInTree(TreeNode* root) {root->val = 0;vector<TreeNode*> que;que.push_back(root);while (!que.empty()) {vector<TreeNode*> nxt;ll sum = 0;for (auto node : que) {if (node->left) {nxt.push_back(node->left);sum += node->left->val;}if (node->right) {nxt.push_back(node->right);sum += node->right->val;}}for (auto node : que) {ll chiSum = 0;if (node->left) {chiSum += node->left->val;}if (node->right) {chiSum += node->right->val;}if (node->left) {node->left->val = sum - chiSum;}if (node->right) {node->right->val = sum - chiSum;}}que = move(nxt);}return root;}
};
17. 919. 完全二叉树插入器(中等)

919. 完全二叉树插入器 - 力扣(LeetCode)

思想

1.完全二叉树 是每一层(除最后一层外)都是完全填充(即,节点数达到最大)的,并且所有的节点都尽可能地集中在左侧。
设计一种算法,将一个新节点插入到一棵完全二叉树中,并在插入后保持其完整。
实现 CBTInserter 类:

  • CBTInserter(TreeNode root) 使用头节点为 root 的给定树初始化该数据结构;
  • CBTInserter.insert(int v)  向树中插入一个值为 Node.val == val的新节点 TreeNode。使树保持完全二叉树的状态,并返回插入节点 TreeNode 的父节点的值
  • CBTInserter.get_root() 将返回树的头节点。
    2.利用完全二叉树的性质:
    根节点序号x,左孩子2*x,右孩子2*x+1,(x从1开始计数)
    3.或者队列实现,初始化层序遍历存储叶子节点(倒数第二层的右侧和最后一层的左侧),然后新插入节点进入队尾,队首若有左右子树则出队列
代码
class CBTInserter {
public:TreeNode* curRoot;int size;vector<TreeNode*> nodes;CBTInserter(TreeNode* root) {curRoot = root;nodes.push_back(nullptr);size = 0;queue<TreeNode*> que;que.push(root);while (!que.empty()) {TreeNode* cur = que.front();que.pop();++size;nodes.push_back(cur);if (cur->left)que.push(cur->left);if (cur->right)que.push(cur->right);}}int insert(int val) {++size;int fa = size / 2;TreeNode* faNode = nodes[fa];TreeNode* newNode = new TreeNode(val);nodes.push_back(newNode);if (size % 2)faNode->right = newNode;elsefaNode->left = newNode;return faNode->val;}TreeNode* get_root() { return curRoot; }
};
18. 958. 二叉树的完全性检验(中等)

958. 二叉树的完全性检验 - 力扣(LeetCode)

思想

1.给你一棵二叉树的根节点 root ,请你判断这棵树是否是一棵 完全二叉树 。
在一棵 完全二叉树 中,除了最后一层外,所有层都被完全填满,并且最后一层中的所有节点都尽可能靠左。最后一层(第 h 层)中可以包含 1 到 2h 个节点。
2.利用一个bool变量来划分非叶子节点与叶子节点

代码
class Solution {
public:bool isCompleteTree(TreeNode* root) {bool isLeaf = false;queue<TreeNode*> que;que.push(root);while (!que.empty()) {TreeNode* cur = que.front();que.pop();if (isLeaf) {if (cur->left || cur->right)return false;} else {if (cur->left == nullptr && cur->right != nullptr) {return false;} else if (cur->right ==nullptr) { // 只要右子树为空(左子树无所谓),则该节点之后剩下节点都是叶子节点isLeaf = true;}if (cur->left)que.push(cur->left);if (cur->right)que.push(cur->right);}}return true;}
};
http://www.dtcms.com/a/517038.html

相关文章:

  • 免费h5网站模版泸州中泸建设集团有限公司网站
  • compilesdk是Android11的compose项目
  • 连云港网站 建设seo刷关键词排名工具
  • 《Java 集合框架全解析!从入门到实战,面试 / 开发都用得上!》
  • 高光谱遥感岩性识别研究进展
  • 刚刚济南发通知南通seo网站诊断
  • 时间服务作业
  • c++ stringstream字符串流的用法
  • 重庆官方网站有哪些南联网站建设哪家好
  • 营销型网站制作费用wordpress 纯静态
  • 探索Objective-C中的对象复制:深入理解copy和mutableCopy
  • Wordpress自建外贸网站网站运营怎么学
  • 最大回撤约束下ETF多因子动态止盈参数校准方案
  • 广东省省考备考(第一百三十天10.22)——科学推理:受力分析(第三节课)
  • Transformer 面试题及详细答案120道(111-120)-- 综合与拓展
  • win网站建设学习网站建设课程
  • 【Android】详细讲解ViewDragHelper的实现原理(不含代码版)
  • 有关学校网站建设策划书个人简历电子版填写免费模板
  • CAS #:1309649-57-7,Biotin-PEG4-azide,生物素-PEG4-叠氮
  • 什么是搜索引擎百度sem优化师
  • 防重复提交的Token机制需求测试点
  • 李宏毅机器学习笔记29
  • 羊驼免疫平台:纳米抗体制备的天然基石与实践挑战深度解析
  • 【YOLO11-obb部署至RK3588】模型训练→转换RKNN→开发板部署
  • 怎么建立公司网站平台南通微信网站开发
  • nodejs可以做企业网站吗wordpress xcache
  • AI Agent结合机器学习与深度学习在全球气候变化驱动因素预测中的应用
  • 基于 GEE 使用 OTSU 算法赋能遥感水体自动化提取:从自动阈值计算到高效分割的水体自动分割方案
  • 网站开发的项目总结汕头网站建设方案开发
  • 网站做好了怎么做后台wordpress设置弹窗