【算法专题训练】27、树的层序遍历
1、LCR 044. 在每个树行中找最大值
题目信息:
- https://leetcode.cn/problems/hPov7L/description/
给定一棵二叉树的根节点 root ,请找出该二叉树中每一层的最大值。示例 1:
输入: root = [1,3,2,5,3,null,9]
输出: [1,3,9]
解释:1/ \3 2/ \ \5 3 9示例 2:
输入: root = [1,2,3]
输出: [1,3]
解释:1/ \2 3示例 3:
输入: root = [1]
输出: [1]示例 4:
输入: root = [1,null,2]
输出: [1,2]
解释:1\2示例 5:
输入: root = []
输出: []提示:
二叉树的节点个数的范围是 [0,104]
-231 <= Node.val <= 231 - 1
2、解题思路:
解法1:空节点占位法
- 1、审题:
- 输入一棵二叉树,要求找到二叉树每一层节点中的最大值,组成一个集合并返回
- 2、解题:
- 核心在于遍历树的每一层节点,并从中找到最大值
- 可以通过树的层序遍历,问题在于如何知道刚好遍历完树的一层结点?
- 解法1:在遍历的过程中,每层遍历完插入一个空的结点,当遍历到空节点时,就取出最大值
代码实现:
vector<int> largestValues(TreeNode *root)
{std::vector<int> res;std::queue<TreeNode *> queue;if (root == nullptr){return res;}queue.push(root);queue.push(nullptr);int max = INT32_MIN;while (!queue.empty()){TreeNode *node = queue.front();queue.pop();if (node == nullptr){if (!queue.empty()){queue.push(nullptr);}res.push_back(max);max = INT32_MIN;}else{// 不为空,取出该结点max = std::max(node->val, max);if (node->left != nullptr){queue.push(node->left);}if (node->right != nullptr){queue.push(node->right);}}}return res;
}
解法2:双计数法
- 在层序遍历过程中,记录每层的数量,使用两个变量current和next
- current标记当前层的结点个数,next记录下一层结点的个数,遍历的时候当前层个数current不断减少,next的值不断增加
- 当current为0时,说明当前层所有结点都遍历完成后,此时获取出这一层的最大值保存到集合中,并将current的值设置为next的值,从而开始下一层级的遍历
- 其实next的值就等于遍历过程中队列中元素的个数
代码实现:
vector<int> largestValues(TreeNode *root)
{std::vector<int> res;std::queue<TreeNode *> queue;int current = 0;int next = 0;int max = INT32_MIN;if (root == nullptr){return res;}// 根节点入队列queue.push(root);current = 1;while (!queue.empty()){TreeNode *node = queue.front();queue.pop();if (node->left != nullptr){queue.push(node->left);next++;}if (node->right != nullptr){queue.push(node->right);next++;}// 计算处理current--;max = std::max(max, node->val);if (current == 0){res.push_back(max);current = next;next = 0;max = INT32_MIN;}}return res;
}
解法3:单计数法
- 使用一个计数值current保存当前层的结点个数,在遍历完当前层的时候,将队列中元素个数赋值给current
代码实现:
vector<int> largestValues(TreeNode *root)
{std::vector<int> res;std::queue<TreeNode *> queue;int current = 0;int max = INT32_MIN;if (root == nullptr){return res;}// 根节点入队列queue.push(root);current = 1;while (!queue.empty()){TreeNode *node = queue.front();queue.pop();if (node->left != nullptr){queue.push(node->left);}if (node->right != nullptr){queue.push(node->right);}// 计算处理current--;max = std::max(max, node->val);if (current == 0) // 当前一层遍历完了{res.push_back(max);current = queue.size();max = INT32_MIN;}}return res;
}
解法4:双队列法
- 解法3使用current值来标记当前层的个数,也可以采用两个队列来替换,当前队列保存当前层需要遍历的元素
- next队列保存下一层需要遍历的元素,当current的值减少为0时,进行队列的替换
代码实现:
vector<int> largestValues(TreeNode *root)
{std::queue<TreeNode *> currQueue;std::queue<TreeNode *> nextQueue;int max = INT32_MIN;int current = 0;std::vector<int> res;if (root == nullptr){return res;}currQueue.push(root);current = 1;while (!currQueue.empty()){TreeNode *node = currQueue.front();currQueue.pop();if (node->left != nullptr){nextQueue.push(node->left);}if (node->right != nullptr){nextQueue.push(node->right);}current--;max = std::max(max, node->val);if (current == 0){res.push_back(max);currQueue = nextQueue;current = currQueue.size();nextQueue = std::queue<TreeNode *>();max = INT32_MIN;}}return res;
}
3、总结
- 层序遍历,找每一层结点的最大值,核心问题在于如何确定遍历完一层的结点了
- 上面提供了四种解法,个人单计数法最合适
