前言
本文展示LeetCode中与二叉树广度优先遍历(层序遍历)的变体相关的题目,读者可以用来借此默写以检验是否熟悉相关算法,其难度为简单或中等,我们会给出最基础的层序遍历算法,然后推荐读者熟练掌握相关变体算法。
LeetCode题目 | 相关题目类型 | 相关链接 |
102 | 二叉树的层序遍历-按层输出(中等难度) | https://leetcode-cn.com/problems/binary-tree-level-order-traversal/ |
107 | 二叉树的层序遍历II-按层反转输出(中等难度) | https://leetcode-cn.com/problems/binary-tree-level-order-traversal-ii/ |
199 | 二叉树的右视图-按层输出最后一个(中等难度) | https://leetcode-cn.com/problems/binary-tree-right-side-view/ |
637 | 二叉树的层平均值-按层取均值(简单难度) | https://leetcode-cn.com/problems/average-of-levels-in-binary-tree/ |
429 | N叉树的层序遍历-按层输出(中等难度) | https://leetcode-cn.com/problems/n-ary-tree-level-order-traversal/ |
515 | 在每个树行中找最大值-按层取最大值(中等难度) | https://leetcode-cn.com/problems/find-largest-value-in-each-tree-row/ |
116 | 填充每个节点的下一个右侧结点指针(中等难度) | https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node/ |
117 | 填充每个节点的下一个右侧结点指针II(中等难度) | https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node-ii/ |
虽然上述有8道题目,但是最根本的是第一道题目,请读者在理解第一道题目的基础上做其他7道就会非常容易。
一、最简单的层序遍历
假设我们有如下二叉树:
如果希望经过层序遍历得到连续输出[3,9,20,15,7]
我们之前已经讲解过该算法的迭代实现,可以借助队列仿照先序遍历流程:
即“层序遍历同先序,借用队列先左右”,
相关Python3代码如下:
def levelOrder(self, root: TreeNode) -> List[List[int]]:
result = []
if not root:
return result
queue = [root]
while len(queue)>0:
cur = queue.pop(0)
result.append(cur.val)
if cur.left:
queue.append(cur.left)
if cur.right:
queue.append(cur.right)
return result
对应的C++代码:
vector<int> levelOrder(TreeNode* node) {
vector<int> result;
if (node == NULL) {
return result;
}
queue<TreeNode*> queue;
queue.push(node);
while (!queue.empty()) {
TreeNode* cur = queue.front();
result.push_back(cur->val);
queue.pop();
if (cur->left) {
queue.push(cur->left);
}
if (cur->right) {
queue.push(cur->right);
}
}
return result;
}
二、层序遍历的变体
1、102.⼆叉树的层序遍历(按层输出)
题⽬链接:https://leetcode-cn.com/problems/binary-tree-level-order-traversal/
如果希望经过层序遍历得到按层输出:[[3],[9,20],[15,7]]
我们在上述代码中进行更改,相关Python3代码如下:
def levelOrder(self, root: TreeNode) -> List[List[int]]:
result = []
if not root:
return result
queue = [root]
while len(queue)>0:
length = len(queue)
level_result = []
for i in range(0,length):
cur = queue.pop(0)
level_result.append(cur.val)
if cur.left:
queue.append(cur.left)
if cur.right:
queue.append(cur.right)
result.append(level_result)
return result
我们可以执行代码来理解流程:
第一次循环时,length=1,cur = root ,queue中只有root=3,将其出队,root.val加入level_result
cur.left和cur.right都存在,加入队列,此时队列中有第二层的两个节点;
第二次循环时,length=2,cur = 9节点时 ,将其出队加入level_result,然后左右节点不存在不需要添加;
cur = 20节点时 ,将其出队加入level_result,然后左右节点存在需要添加到队列,此时队列中有第三层的两个节点;
即每次循环,第一层循环负责循环二叉树的每一层,第二层循环负责循环二叉树的每一层的节点,并将下一层节点加入队列。
这里给出C++代码:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> result;
if(root==NULL){
return result;
}
queue<TreeNode*> queue;
queue.push(root);
while(!queue.empty()){
int size = queue.size();
vector<int> level_result;
for(int i=0;i<size;i++){
TreeNode* cur=queue.front();
queue.pop();
level_result.push_back(cur->val);
if (cur->left!=NULL){
queue.push(cur->left);
}
if (cur->right!=NULL){
queue.push(cur->right);
}
}
result.push_back(level_result);
}
return result;
}
2、107.⼆叉树的层序遍历(按层反转输出)
题⽬链接:https://leetcode-cn.com/problems/binary-tree-level-order-traversal-ii/
该题希望经过层序遍历得到按层反转输出:[[15,7],[9,20],[3]]
最简单的做法就是在之前代码返回result前添加反转操作。
C++需要在“return result;”前添加如下语句:
reverse(result.begin(),result.end());
Python需要在“return result;”前添加如下语句:
result = result[::-1]
3、199.⼆叉树的右视图(按层输出最后一个)
题⽬链接:https://leetcode-cn.com/problems/binary-tree-right-side-view/
该题描述如下:
该题非常简单,在每层加入result时,只加入每层最后一个即可。
C++版本:
vector<int> rightSideView(TreeNode* root) {
vector<int> result;
if(root==NULL){
return result;
}
queue<TreeNode*> queue;
queue.push(root);
while(!queue.empty()){
int size = queue.size();
for(int i=0;i<size;i++){
TreeNode* cur=queue.front();
queue.pop();
if(i==size-1){
result.push_back(cur->val);
}
if (cur->left!=NULL){
queue.push(cur->left);
}
if (cur->right!=NULL){
queue.push(cur->right);
}
}
}
return result;
}
Python版本:
def rightSideView(self, root: TreeNode) -> List[int]:
result = []
if not root:
return result
queue = [root]
while len(queue)>0:
length = len(queue)
for i in range(0,length):
cur = queue.pop(0)
if i==length-1:
result.append(cur.val)
if cur.left:
queue.append(cur.left)
if cur.right:
queue.append(cur.right)
return result
4、637.⼆叉树的层平均值(按层取平均值)
题⽬链接:https://leetcode-cn.com/problems/average-of-levels-in-binary-tree/
该题描述如下:
该题只要把每层的数累加起来求均值即可,注意C++要将sum定义为double,不然精度不足。
C++版本:
vector<double> averageOfLevels(TreeNode* root) {
vector<double> result;
if(root==NULL){
return result;
}
queue<TreeNode*> queue;
queue.push(root);
while(!queue.empty()){
int size = queue.size();
double sum = 0;
for(int i=0;i<size;i++){
TreeNode* cur=queue.front();
queue.pop();
sum+=cur->val;
if (cur->left!=NULL){
queue.push(cur->left);
}
if (cur->right!=NULL){
queue.push(cur->right);
}
}
result.push_back(sum/size);
}
return result;
}
Python版本:
def averageOfLevels(self, root: TreeNode) -> List[float]:
result = []
if not root:
return result
queue = [root]
while len(queue)>0:
length = len(queue)
sum=0.0
for i in range(0,length):
cur = queue.pop(0)
sum+=cur.val
if cur.left:
queue.append(cur.left)
if cur.right:
queue.append(cur.right)
result.append(sum/length)
return result
5、429.N叉树的层序遍历(按层输出)
题⽬链接:https://leetcode-cn.com/problems/n-ary-tree-level-order-traversal/
该题描述如下:
该题只要把遍历一下children数组即可。
C++版本:
vector<vector<int>> levelOrder(Node* root) {
vector<vector<int>> result;
if(root==NULL){
return result;
}
queue<Node*> queue;
queue.push(root);
while(!queue.empty()){
int size = queue.size();
vector<int> level_result;
for(int i=0;i<size;i++){
Node* cur=queue.front();
queue.pop();
level_result.push_back(cur->val);
for(int j=0;j<cur->children.size();j++){
if (cur->children[j]!=NULL){
queue.push(cur->children[j]);
}
}
}
result.push_back(level_result);
}
return result;
}
Python版本:
def levelOrder(self, root: 'Node') -> List[List[int]]:
result = []
if not root:
return result
queue = [root]
while len(queue)>0:
length = len(queue)
level_result = []
for i in range(0,length):
cur = queue.pop(0)
level_result.append(cur.val)
for child in cur.children:
if child:
queue.append(child)
result.append(level_result)
return result
6、515.在每个树⾏中找最⼤值(按层输出)
题⽬链接:https://leetcode-cn.com/problems/find-largest-value-in-each-tree-row/
该题描述如下:
该题需要注意的是,取最大值,最大值的初始值要设置为整数的最小值。
在C++中为INT_MIN,在Python中为-sys.maxsize - 1。
C++版本:
vector<int> largestValues(TreeNode* root) {
vector<int> result;
if(root==NULL){
return result;
}
queue<TreeNode*> queue;
queue.push(root);
while(!queue.empty()){
int size = queue.size();
int max = INT_MIN;
for(int i=0;i<size;i++){
TreeNode* cur=queue.front();
queue.pop();
if (max<cur->val){
max = cur->val;
}
if (cur->left!=NULL){
queue.push(cur->left);
}
if (cur->right!=NULL){
queue.push(cur->right);
}
}
result.push_back(max);
}
return result;
}
Python版本:
def largestValues(self, root: TreeNode) -> List[int]:
result = []
if not root:
return result
queue = [root]
while len(queue)>0:
length = len(queue)
max=-sys.maxsize - 1
for i in range(0,length):
cur = queue.pop(0)
if max<cur.val:
max=cur.val
if cur.left:
queue.append(cur.left)
if cur.right:
queue.append(cur.right)
result.append(max)
return result
7、116.填充每个节点的下⼀个右侧节点指针(按层输出)
题⽬链接:https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node/
该题描述如下:
该题需要注意的是理解题目,输入root,返回root,二叉树的存储结构要改变。
C++版本:
Node* connect(Node* root) {
if(root==NULL){
return root;
}
queue<Node*> queue;
queue.push(root);
while(!queue.empty()){
int size = queue.size();
vector<Node*> level_node;//记录每层的node
for(int i=0;i<size;i++){
Node* cur=queue.front();
queue.pop();
level_node.push_back(cur);
if (cur->left!=NULL){
queue.push(cur->left);
}
if (cur->right!=NULL){
queue.push(cur->right);
}
}
//连接next
for(int i=0;i<size;i++){
if (i==size-1){
level_node[i]->next = NULL;
}
else{
level_node[i]->next = level_node[i+1];
}
}
}
return root;
}
Python版本:
def connect(self, root: 'Node') -> 'Node':
if not root:
return root
queue = [root]
while len(queue)>0:
length = len(queue)
level_node = []
for i in range(0,length):
cur = queue.pop(0)
level_node.append(cur)
if cur.left:
queue.append(cur.left)
if cur.right:
queue.append(cur.right)
for i in range(0,length):
if i==length-1:
level_node[i].next=None
else:
level_node[i].next=level_node[i+1]
return root
8、116.填充每个节点的下⼀个右侧节点指针II(按层输出)
题⽬链接:https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node-ii/
该题描述如下:
该题需要注意的是理解题目,输入root,返回root,二叉树的存储结构要改变。
该题目本质上和上一道区别不大,可以直接使用上一道题的答案,但是这里我们给出一个改进版本。
C++版本:
Node* connect(Node* root) {
if(root==NULL){
return root;
}
queue<Node*> queue;
queue.push(root);
while(!queue.empty()){
int size = queue.size();
vector<Node*> level_node;//记录每层的node
Node* pre;
Node* cur;
for(int i=0;i<size;i++){
cur=queue.front();
queue.pop();
if(i!=0){
pre->next = cur;
}
pre= cur;
if (cur->left!=NULL){
queue.push(cur->left);
}
if (cur->right!=NULL){
queue.push(cur->right);
}
}
}
return root;
}
Python版本:
def connect(self, root: 'Node') -> 'Node':
if not root:
return root
queue = [root]
while len(queue)>0:
length = len(queue)
pre = None
cur = None
for i in range(0,length):
cur = queue.pop(0)
if i!=0:
pre.next = cur
pre = cur
if cur.left:
queue.append(cur.left)
if cur.right:
queue.append(cur.right)
return root