中等
给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。
这个题只要一想通其实就很简单了,无论你这个二叉树有多么庞大和繁杂,归根到底根节点只有一个,第二层最多两个结点,我们先将根节点加入队列。当循环不为空的时候,记录当前队列大小size,循环size次,队列依次弹出节点,并访问弹出节点的左右子树,依次将左右子树加入队列,记录当前队列大小size,循环size次,队列依次弹出节点,并访问弹出节点的左右子树……注意,并不是说,队列里只有一层的节点(应该是有两层),队列里可能同时放着第一层节点和第二层节点,我们是依靠size的大小来记住哪些节点是哪一层的。
// 迭代解法
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res = new LinkedList<>();
if (root == null) {
return res;
}
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
// while 循环控制从上向下一层层遍历
while(!q.isEmpty()){
int size = q.size();
TreeNode curNode;
List<Integer> temp = new LinkedList<>(); //用来记录该层的节点值
// for 循环控制每一层从左向右遍历
for (int i = 0; i < size; i++) {
curNode = q.poll();
temp.add(curNode.val);
// 不断地把该层的不为空的孩子结点加入队列
if(curNode.left != null) q.offer(curNode.left);
if(curNode.right != null) q.offer(curNode.right);
}
res.add(temp);
}
return res;
}
}
// DFS 递归方式的解法
class Solution {
List<List<Integer>> res = new LinkedList<>(); // 最终结果存在这里
public List<List<Integer>> levelOrder(TreeNode root) {
checkFun(root, 0);
return res;
}
public void checkFun(TreeNode node, int deep){
// 传进来的节点为空,直接返回
if (node == null) return;
// 传进来的节点不为空,继续操作
deep++; //既然该层节点不为空,那么层数就应该加一
// 如果结果链表的深度比当前deep还小,那么就给它加一层
if (res.size() < deep){
List<Integer> level = new LinkedList<>();
res.add(level);
}
// 利用list的索引值进行层级界定
// deep其实和res.size()是一样的,但是索引是从0开始的,所以要减一
res.get(deep - 1).add(node.val);
checkFun(node.left, deep);
checkFun(node.right, deep);
}
}
以下题目为黑体的几题都可以用上述代码改一下秒了:
107. 二叉树的层序遍历 II
中等
给你二叉树的根节点 root ,返回其节点值 自底向上的层序遍历 。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历
class Solution {
public List<List<Integer>> levelOrderBottom(TreeNode root) {
List<List<Integer>> res = new LinkedList<>();
if (root == null) {
return res;
}
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
// while 循环控制从上向下一层层遍历
while(!q.isEmpty()){
int size = q.size();
TreeNode curNode;
List<Integer> temp = new LinkedList<>(); //用来记录该层的节点值
// for 循环控制每一层从左向右遍历
for (int i = 0; i < size; i++) {
curNode = q.poll();
temp.add(curNode.val);
// 不断地把该层的不为空的孩子结点加入队列
if(curNode.left != null) q.offer(curNode.left);
if(curNode.right != null) q.offer(curNode.right);
}
// 新遍历到的层插到头部, 这样就满足按照层次反序的要求
res.addFirst(temp);
}
return res;
}
}
199. 二叉树的右视图
中等
给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
class Solution {
public List<Integer> rightSideView(TreeNode root) {
List<Integer> res = new LinkedList<>();
if (root == null) {
return res;
}
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
// while 循环控制从上向下一层层遍历
while(!q.isEmpty()){
int size = q.size();
TreeNode curNode;
// for 循环控制每一层从左向右遍历
for (int i = 0; i < size; i++) {
curNode = q.poll();
if (i == size - 1) res.add(curNode.val);// 记录这一层的最右边的数
// 不断地把该层的不为空的孩子结点加入队列
if(curNode.left != null) q.offer(curNode.left);
if(curNode.right != null) q.offer(curNode.right);
}
}
return res;
}
}
637. 二叉树的层平均值
简单
给定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值。与实际答案相差 10-5 以内的答案可以被接受
class Solution {
public List<Double> averageOfLevels(TreeNode root) {
List<Double> res = new LinkedList<>();
if (root == null) {
return res;
}
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
// while 循环控制从上向下一层层遍历
while(!q.isEmpty()){
int size = q.size();
TreeNode curNode;
double sum = 0; //用来记录该层的节点和,记住是double类型!!
// for 循环控制每一层从左向右遍历
for (int i = 0; i < size; i++) {
curNode = q.poll();
sum += curNode.val;// 记录节点值
// 不断地把该层的不为空的孩子结点加入队列
if(curNode.left != null) q.offer(curNode.left);
if(curNode.right != null) q.offer(curNode.right);
}
res.add(sum / size);
}
return res;
}
}
429. N 叉树的层序遍历
中等
给定一个 N 叉树,返回其节点值的层序遍历。(即从左到右,逐层遍历)。
树的序列化输入是用层序遍历,每组子节点都由 null 值分隔(参见示例)。
class Solution {
public List<List<Integer>> levelOrder(Node root) {
List<List<Integer>> res = new LinkedList<>();
if (root == null) {
return res;
}
Queue<Node> q = new LinkedList<>();
q.offer(root);
// while 循环控制从上向下一层层遍历
while(!q.isEmpty()){
int size = q.size();
Node curNode;
List<Integer> temp = new LinkedList<>(); //用来记录该层的节点值
// for 循环控制每一层从左向右遍历
for (int i = 0; i < size; i++) {
curNode = q.poll();
temp.add(curNode.val);
// 不断地把该层的不为空的孩子结点加入队列
List<Node> kids = curNode.children;
if (kids != null){ // 可以不加这行
for (Node kid : kids){
if (kid != null) q.offer(kid);
}
}
}
res.add(temp);
}
return res;
}
}
515. 在每个树行中找最大值
中等
给定一棵二叉树的根节点 root ,请找出该二叉树中每一层的最大值
class Solution {
public List<Integer> largestValues(TreeNode root) {
List<Integer> res = new LinkedList<>();
if (root == null) {
return res;
}
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
// while 循环控制从上向下一层层遍历
while(!q.isEmpty()){
int size = q.size();
TreeNode curNode;
int levelMax = Integer.MIN_VALUE; //用来记录该层的最大节点值
// for 循环控制每一层从左向右遍历
for (int i = 0; i < size; i++) {
curNode = q.poll();
levelMax = levelMax > curNode.val ? levelMax : curNode.val;
// 不断地把该层的不为空的孩子结点加入队列
if(curNode.left != null) q.offer(curNode.left);
if(curNode.right != null) q.offer(curNode.right);
}
res.add(levelMax);
}
return res;
}
}
116. 填充每个节点的下一个右侧节点指针
中等
给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:
struct Node {
int val;
Node *left;
Node *right;
Node *next;
}
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。
初始状态下,所有 next 指针都被设置为 NULL
class Solution {
public Node connect(Node root) {
if (root == null) {
return root;
}
Queue<Node> q = new LinkedList<>();
q.offer(root);
// while 循环控制从上向下一层层遍历
while(!q.isEmpty()){
int size = q.size();
Node curNode;
// for 循环控制每一层从左向右, 让他们的指针指向右方
for (int i = 0; i < size; i++) {
curNode = q.poll();
if (i == size - 1) {
curNode.next = null;
} else {
curNode.next = q.peek();
}
// 不断地把该层的不为空的孩子结点加入队列
if(curNode.left != null) q.offer(curNode.left);
if(curNode.right != null) q.offer(curNode.right);
}
}
return root;
}
}
117. 填充每个节点的下一个右侧节点指针 II
中等
给定一个二叉树:
struct Node {
int val;
Node *left;
Node *right;
Node *next;
}
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL 。
初始状态下,所有 next 指针都被设置为 NULL
class Solution {
public Node connect(Node root) {
if (root == null) {
return root;
}
Queue<Node> q = new LinkedList<>();
q.offer(root);
while (!q.isEmpty()){
Node cur;
int sz = q.size();
for (int i = 0; i < sz; i++){
cur = q.poll();
if (i == sz - 1){
cur.next = null;
} else {
cur.next = q.peek();
}
if (cur.left != null) q.offer(cur.left);
if (cur.right != null) q.offer(cur.right);
}
}
return root;
}
}
简单
给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点
// 前序递归遍历翻转
class Solution {
/**
* 前后序遍历都可以
* 中序不行,因为先左孩子交换孩子,再根交换孩子(做完后,右孩子已经变成了原来的左孩子),再右孩子交换孩子(此时其实是对原来的左孩子做交换)
*/
public TreeNode invertTree(TreeNode root) {
preOrder(root);
return root;
}
public void preOrder(TreeNode node){
if (node == null) {
return;
}
TreeNode temp;
// 翻转节点
temp = node.left;
node.left = node.right;
node.right = temp;
// 上面的4行代码处理了当前节点,下面两行的处理左右节点,所以是前序遍历,如果上下交换那就是后序遍历了
preOrder(node.left);
preOrder(node.right);
}
简单
给你一个二叉树的根节点 root , 检查它是否轴对称。
class Solution {
public boolean isSymmetric(TreeNode root) {
// 检查二叉树是否对称,最关键的点是,将这个树从根节点劈开,形成两个分别以根节点的左右节点为根节点的子树,然后采用遍历的方法,检查两棵子树是否一致
return compare(root.left, root.right);
}
// 其实这个递归的函数,每次只能比较一对轴对称的节点
public boolean compare(TreeNode left, TreeNode right){
//递归的终止条件是两个节点都为空
//或者两个节点中有一个为空
//或者两个节点的值不相等
if (left == null && right == null) {
return true;
}
if (left == null && right != null) {
return false;
}
if (left != null && right == null) {
return false;
}
if (left.val != right.val) {
return false;
}
// 上面这两个节点比较完毕了,继续比较他们的左右节点是否一致
boolean boolOutside = compare(left.left, right.right); //比较外侧
boolean boolInside = compare(left.right, right.left); //比较外侧
return boolInside && boolOutside; //只有内侧外侧都一致,才能返回true
}
}