题目102. 二叉树的层序遍历 - 力扣(LeetCode)
二叉树的层序遍历:逐层,从左到右的访问所有节点
思路
用队列来存储节点,先进先出;用int size = 1记录每一层的元素个数,逐层遍历后清零
- 根节点入队,offer(root)
- 外层循环
!queue.isEmpty()控制遍历所有节点,更新当前size,初始化每层结果为空数组 - 内层循环
size--控制遍历每层节点,每个节点处理逻辑:poll(node),若node.left非空,则offer(node.left)若node.left非空,则offer(node.left) - 内层循环结束后,更新结果数组result
代码
下一次内层循环开始前,需要更新当前层元素个数size,具体代码实现有很多种方法
第一种: 在内层循环开始前,更新size = queue.size()
第二种: 在内层循环里计数cnt,内层循环结束后,size = cnt
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
Queue<TreeNode> queue = new LinkedList<>();
List<List<Integer>> res = new ArrayList<>();
if(root == null) {
return res;
}
queue.offer(root);
int size = 1;
while(!queue.isEmpty()) {
List<Integer> a = new ArrayList<>();
size = queue.size();
// int cnt = 0;
for(;size > 0;size--){
TreeNode node = queue.poll();
a.add(node.val);
if(node.left != null) {
queue.offer(node.left);
// cnt++;
}
if(node.right != null) {
queue.offer(node.right);
// cnt++;
}
}
res.add(a);
}
return res;
}
}
总结:
层序遍历的定义不难理解,需要利用队列的先进先出特性,来保存每层节点,配合size内层循环,实现每层节点的记录
学习时长:50min
补充题
429. N 叉树的层序遍历 - 力扣(LeetCode)
中等-学习时间30min
思路
层序遍历同样的思路,两层循环
- 外层循环控制队列所有节点的遍历
- 内层循环控制每一层节点遍历
- 这道题比较绕的是子节点是一个List集合,利用增强for循环,需要初始化
for(Node i : nodelist)
代码
/*
// Definition for a Node.
class Node {
public int val;
public List<Node> children;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val, List<Node> _children) {
val = _val;
children = _children;
}
};
*/
class Solution {
public List<List<Integer>> levelOrder(Node root) {
Queue<Node> queue = new LinkedList<>();
List<List<Integer>> res = new ArrayList<>();
if(root == null) return res;
queue.offer(root);
int size = 1;
while(!queue.isEmpty()) {
List<Integer> a = new ArrayList<>();
size = queue.size();
for(;size > 0;size--) {
Node node = queue.poll();
a.add(node.val);
List<Node> nodelist = node.children;
for(Node i : nodelist) {
if(i != null) {
queue.offer(i);
}
}
}
// a.add(null);
res.add(a);
}
return res;
}
}
107. 二叉树的层序遍历 II - 力扣(LeetCode)
自下而上遍历每一层
中等-学习时间40min
思路
层序遍历同样的思路,两层循环
- 外层循环控制队列所有节点的遍历
- 内层循环控制每一层节点遍历
- 这道题需要自下而上遍历,得到结果后反转,这似乎没有难度,但是增加了空间复杂度
解决办法:利用java的链表数据结构ArrayList,在头部插入元素的时间复杂度是O(1)
代码
ArrayList在头部插入元素res.add(0,level)
class Solution {
public List<List<Integer>> levelOrderBottom(TreeNode root) {
Queue<TreeNode> queue = new LinkedList<>();
List<List<Integer>> res = new ArrayList<>();
if(root == null) return res;
int size = 1;
queue.offer(root);
while(!queue.isEmpty()) {
List<Integer> level = new ArrayList<>();
size = queue.size();
for(;size > 0;size--) {
TreeNode node = queue.poll();
level.add(node.val);
if(node.left != null) {
queue.offer(node.left);
}
if(node.right != null) {
queue.offer(node.right);
}
}
res.add(0,level);
}
return res;
}
}
199. 二叉树的右视图 - 力扣(LeetCode)
中等-学习时间6min
思路
层序遍历同样的思路,两层循环
- 外层循环控制队列所有节点的遍历
- 内层循环控制每一层节点遍历
- 这道题需要记录每一层的最后一个元素
代码
class Solution {
public List<Integer> rightSideView(TreeNode root) {
Queue<TreeNode> queue = new LinkedList<>();
List<Integer> result = new ArrayList<>();
if(root == null) return result;
int size = 1;
queue.offer(root);
while(!queue.isEmpty()) {
size = queue.size();
for(;size > 0;size--) {
TreeNode node = queue.poll();
if(node.left != null) {
queue.offer(node.left);
}
if(node.right != null) {
queue.offer(node.right);
}
if(size == 1) {
result.add(node.val);
}
}
}
return result;
}
}
637. 二叉树的层平均值 - 力扣(LeetCode)
简单-学习时间20min
思路
层序遍历同样的思路,两层循环
- 外层循环控制队列所有节点的遍历
- 内层循环控制每一层节点遍历
- 这道题需要记录每一层的平均值
代码
double sum = 0;如果用int,如果和超过整型最大值2147483647,导致测试样例不过- 这里用cnt来存储size的值,其实可以用i作为内层循环变量
for(int i = 0;i<size;i++),同样可以遍历内层循环的所有元素,同时不需要用cnt来存储size值,避免意义重复。
class Solution {
public List<Double> averageOfLevels(TreeNode root) {
Queue<TreeNode> queue = new LinkedList<>();
List<Double> result = new ArrayList<>();
if(root == null) return result;
int size = 1;
queue.offer(root);
while(!queue.isEmpty()) {
size = queue.size();
int cnt = size;
double sum = 0;
for(;size > 0;size--) {
TreeNode node = queue.poll();
sum += node.val;
if(node.left != null) {
queue.offer(node.left);
}
if(node.right != null) {
queue.offer(node.right);
}
}
result.add(sum/cnt);
}
return result;
}
}
补充知识点
类型转换
- 自动类型转换:也叫隐式转换
转换的条件:若不同数据类型可以兼容,而且目标值的数据类型范围大于操作数的数据类型-->可以发生转换
转换的场景:在运算中,所有的数都要转化成同一种数据类型,此时会发生自动类型转换,将低级类型数据向高级类型数据转换。
- 数字:byte-->short-->int-->long-->float-->double
- 字符:char-->int
- 特殊:char(-->int-->long-->float)-->double
上面代码中sum/cnt,sum是double类型,cnt是int类型,那么结果是什么类型?
答:double类型
- 强制类型转换:也叫显式转化
转换的条件:若不同数据类型可以兼容,但目标值范围更小
转换的场景:程序中虽然出现double类型,但是结果希望以int类型存储;可能导致精度丢失