前言
这是[LeetCode精选Top面试]系列文章的第1篇/145篇。
在这个系列中,我们会按照题目类别进行总结。对于每一道题目,会给出一种或多种的算法思路,以及最精炼、最高效的代码。如果代码中涉及到语言上的语法知识,我们也会在知识扩展小节中进行详解。
在每个系列介绍完成之后,我们会再次回顾总结,提炼出通用解法和代码模板。
希望各位持续关注本系列,和我们一起前进,DayDayUp~
一、题目
给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。
例如:
给定二叉树: [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回其层次遍历结果:
[
[3],
[9,20],
[15,7]
]
二、思路分析
解法一:广度优先搜索BFS
广度优先搜索是从树的根节点开始,沿着树的宽度来遍历树的节点。如果所有节点均被访问,则算法中止。广度优先搜索通常采用队列来辅助实现。
在题目中要求按照层序遍历,实现逐层地从左向右访问所有的结点。这正好符合广度优先搜索的策略。
我们可以立即想到普通广度优先搜索的模板:
vector<int> bfs(TreeNode* root) {
std::vector<int> result;
if(!root){
return result;
}
queue<TreeNode*> q;
q.push(root);
while(!q.empty()){
TreeNode* node = q.front();
q.pop();
result.emplace_back(node->val);
if(node->left){
q.push(node->left);
}
if(node->right){
q.push(node->right);
}
}
return result;
}
但是,这里返回的是一个一维数组,和题目要求的二维数组不一致。因此,我们需要稍作修改,修改内容如下:
- 在while循环每次遍历时,获取队列的长度N(即队列中的节点个数)
- 一次性的处理这N个节点,然后再进入下一轮循环。
通过这种修改,确保每次循环时要处理的队列中元素都是本层的元素。
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> result;
if(!root){
return result;
}
queue<TreeNode*> q;
q.push(root);
while(!q.empty()){
vector<int> tmp;
// 每次q.size() 获取的都是队列的长度(一个层的节点个数)
for(int i = q.size(); i > 0 ; i--){
TreeNode* node = q.front();
q.pop();
tmp.emplace_back(node->val);
if(node->left) q.push(node->left);
if(node->right) q.push(node->right);
}
result.emplace_back(tmp);
}
return result;
}
复杂度分析:
- 时间复杂度:每个节点元素进队和出队操作各一次,时间复杂度为 O ( N ) O(N) O(N)。
- 空间复杂度:队列最大存储个数小于等于N,空间复杂度为 O ( N ) O(N) O(N)。
解法二:深度优先搜索DFS
本题也可以使用深度优先搜索来实现。
深度优先搜索是采用栈或者递归来实现。(递归在系统内部也是基于栈来实现)
vector<vector<int>> levelOrder(TreeNode* root) {
std::vector<std::vector<int>> res;
if(!root) return res;
dfs(0, root, res);
return res;
}
// index 是节点所在层的层索引
void dfs(int index, TreeNode* node, std::vector<std::vector<int>>& res){
// node 应该放到res[index]中, 如果res[index]元素不存在, 需要先创建一个
if(res.size() < index + 1){
res.push_back({});
}
res[index].emplace_back(node->val);
if(node->left){
dfs(index+1, node->left, res);
}
if(node->right){
dfs(index+1, node->right, res);
}
}
复杂度分析:
- 时间复杂度:在递归过程中每个节点只访问一次,所以时间复杂度为 O ( N ) O(N) O(N)。
- 空间复杂度:系统栈的最大存储节点数小于等于N, 所以空间复杂度为 O ( N ) O(N) O(N)。
三、总结
- 了解广度优先搜索和深度优先搜索的思想。
- 了解两种实现的算法模板,广度优先搜索通常使用队列来实现,深度优先搜索通常使用递归实现。
- 能够根据题干的要求,在模板的基础上灵活调整。