文章目录
1.层序遍历
102.二叉树的层序遍历
- 102. 二叉树的层序遍历 | 题目链接
- 思路:队列实现:一层一层的遍历,出队列一个,进它的左右孩子,再出上一层第二个,进第二个的左右孩子。(代码随想录里右很明白的动画演示)
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
//存放结果的列表,每一行单独成列表。
public List<List<Integer>> resList = new ArrayList<List<Integer>>();
//主函数
public List<List<Integer>> levelOrder(TreeNode root) {
checkFun(root);
return resList;
}
//传入根节点
public void checkFun(TreeNode node) {
//剪枝,如果根节点为空,直接返回结果;
if(node == null) {
return;
}
//借助队列,遍历二叉树,把元素往队列里放,先放头节点进来
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.add(node);
//当队列不为空,就要一直循环操作
while(!queue.isEmpty()) {
//创建存放每行元素的列表
List<Integer> itemList = new ArrayList<Integer>();
//记录当前队列里的元素数量(也就是每一个行的元素个数)
int len = queue.size();
//从队列中往外拿出元素,放到每一行的列表中,拿出的个数就是每一行的元素数量
while(len > 0) {
//用临时节点保存队列的头
TreeNode temp = queue.poll();
//把此时的头加入到行列表中
itemList.add(temp.val);
//把它的左右孩子加到队列里
if(temp.left != null) {
queue.offer(temp.left);
}
if(temp.right != null) {
queue.offer(temp.right);
}
//从队列里出一个元素len就--,直到为0,说明已经处理完二叉树中的一行元素了
len--;
}
//把处理完的这一行元素的行列表放到结果列表中,这就处理完一行了
resList.add(itemList);
}
107.二叉树的层序遍历Ⅱ
-
题意:给定一个二叉树,返回其节点值自底向上的层次遍历。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)
-
思路:把上面那道题的结果翻转一下就行
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<List<Integer>> resList = new ArrayList<List<Integer>>();
public List<List<Integer>> levelOrderBottom(TreeNode root) {
rowList(root);
Collections.reverse(resList);//翻转结果!!
return resList;
}
public void rowList(TreeNode root) {
if(root == null) {
return;
}
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);//试了一下,用add和offer都可以
while(!queue.isEmpty()) {
List<Integer> resRow = new ArrayList<>();
int len = queue.size();
while(len-- > 0) {
TreeNode temp = queue.poll();
resRow.add(temp.val);
if(temp.left != null) {
queue.offer(temp.left);
}
if(temp.right != null) {
queue.offer(temp.right);
}
}
resList.add(resRow);
}
}
}
199.二叉树的右视图
- 199.二叉树的右视图 | 题目链接
- 代码随想录 | 题目讲解
- 题意:给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
- 思路:同一套代码,把每一行列表的最后一个元素拿出来放到一个新列表里,这个新列表就是返回的结果列表即可。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<Integer> rightSideView(TreeNode root) {
List<Integer> resList = new ArrayList<>();
if(root == null) {
return resList;
}
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);
while(!queue.isEmpty()) {
List<Integer> row = new ArrayList<>();
int len = queue.size();
while(len-- > 0) {
TreeNode temp = queue.poll();
row.add(temp.val);
if(temp.left != null) {
queue.offer(temp.left);
}
if(temp.right != null) {
queue.offer(temp.right);
}
}
resList.add(row.get(row.size() - 1));//往结果列表里添加行列表的最后一个元素
}
return resList;
}
}
637.二叉树的层平均值
- 637.二叉树的层平均值 | 题目链接
- 题意:给定一个非空二叉树, 返回一个由每层节点平均值组成的数组。
- 思路:求平均值,就不新建行列表了,直接新建一个doule值,把每次遍历的元素加到行和中。注意,循环不能用while了,因为while是用len控制的,len需要一直–,此时应该用for循环,len不变,最后行和/len就是此层的平均值。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<Double> averageOfLevels(TreeNode root) {
List<Double> resList = new ArrayList<>();
if(root == null) {
return resList;
}
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);
while(!queue.isEmpty()) {
int len = queue.size();
double rowSum = 0;
for(int i = 0; i < len; i++) { //不能用while,要保持len不能改变
TreeNode temp = queue.poll();
rowSum += temp.val;//把遍历元素的值加到rowSum层和中
if(temp.left != null) {
queue.offer(temp.left);
}
if(temp.right != null) {
queue.offer(temp.right);
}
}
resList.add(rowSum / len);结果列表里放层平均值
}
return resList;
}
}
429.N叉树的层序遍历
- 429.N叉树的层序遍历 | 题目链接
- 题意:给定一个 N 叉树,返回其节点值的层序遍历。 (即从左到右,逐层遍历)。
- 思路:和最开始的是一样的,只不过没有左右孩子,孩子被统一放在Node这个列表里,直接循环遍历就行。注意for循环的一种写法:for (循环变量类型 循环变量名称 : 要被遍历的对象) 循环体
/*
// 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) {
List<List<Integer>> resList = new LinkedList<List<Integer>>();
if(root == null) {
return resList;
}
Queue<Node> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()) {
List<Integer> row = new ArrayList<>();
int len = queue.size();
for(int i = 0; i < len; i++) {
Node temp = queue.poll();
row.add(temp.val);
List<Node> children = temp.children;
if(children == null || children.size() == 0) {
continue;
} else {
//for (循环变量类型 循环变量名称 : 要被遍历的对象) 循环体
for(Node child : children) {
if(child != null) {
queue.offer(child);
}
}
}
}
resList.add(row);
}
return resList;
}
}
515. 在每个树行中找最大值
- 515. 在每个树行中找最大值 | 题目链接
- 题意:您需要在二叉树的每一行中找到最大的值。
- 思路:层序遍历,取每一层的最大值即可。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<Integer> largestValues(TreeNode root) {
List<Integer> resList = new ArrayList<>();
if(root == null) {
return resList;
}
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);
while(!queue.isEmpty()) {
List<Integer> row = new ArrayList<>();
int len = queue.size();
for(int i = 0; i < len; i++) {
TreeNode temp = queue.poll();
row.add(temp.val);
if(temp.left != null) {
queue.offer(temp.left);
}
if(temp.right != null) {
queue.offer(temp.right);
}
}
resList.add(Collections.max(row)); //把每一行的最大值取出
}
return resList;
}
}
116.填充每个节点的下一个右侧节点指针
-
题意:给定一个完美二叉树,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。初始状态下,所有 next 指针都被设置为 NULL。
-
思路:层序遍历,每一行遍历的时候多加几行指向的代码,让temp.next指向队列的头节点
/*
// Definition for a Node.
class Node {
public int val;
public Node left;
public Node right;
public Node next;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val, Node _left, Node _right, Node _next) {
val = _val;
left = _left;
right = _right;
next = _next;
}
};
*/
class Solution {
public Node connect(Node root) {
if(root == null) {
return root;
}
Queue<Node> queue = new LinkedList<Node>();
queue.offer(root);
while(!queue.isEmpty()) {
int len = queue.size();
for(int i = 0; i < len; i++) {
//取出队首元素
Node temp = queue.poll();
//链接,指定取出的元素指向当前队列中的头
if(i < len - 1) {
temp.next = queue.peek();
}
if(temp.left != null) {
queue.offer(temp.left);
}
if(temp.right != null) {
queue.offer(temp.right);
}
}
}
return root;
}
}
117.填充每个节点的下一个右侧节点指针Ⅱ
- 117.填充每个节点的下一个右侧节点指针Ⅱ | 题目链接
- 题目描述:填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL 。
这道题目说是二叉树,但116题目说是完整二叉树,其实没有任何差别,一样的代码一样的逻辑一样的味道
/*
// Definition for a Node.
class Node {
public int val;
public Node left;
public Node right;
public Node next;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val, Node _left, Node _right, Node _next) {
val = _val;
left = _left;
right = _right;
next = _next;
}
};
*/
class Solution {
public Node connect(Node root) {
if(root == null) {
return root;
}
Queue<Node> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()) {
int len = queue.size();
Node pre = null;
for(int i = 0; i < len; i++) {
Node temp = queue.poll();
//pre为空就表示temp节点是这行的第一个,没有前一个节点指向temp
//pre不为空,就让前一个节点指向temp
if(pre != null) {
pre.next = temp;
}
//让当前节点变成前一个节点
pre = temp;
if(temp.left != null) {
queue.offer(temp.left);
}
if(temp.right != null) {
queue.offer(temp.right);
}
}
}
return root;
}
}
104.二叉树的最大深度
-
题意:给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
-
思路:套用模板
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public int maxDepth(TreeNode root) {
if(root == null) {
return 0;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
int res = 0; //while是按层遍历的,while执行过几次就有几层
while(!queue.isEmpty()) {
int len = queue.size();
for(int i = 0; i < len; i++) {
TreeNode temp = queue.poll();
if(temp.left != null) {
queue.offer(temp.left);
}
if(temp.right != null) {
queue.offer(temp.right);
}
}
res++;
}
return res;
}
}
111.二叉树的最小深度
- 111.二叉树的最小深度 | 题目链接
- 题意:给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public int minDepth(TreeNode root) {
if(root == null) {
return 0;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
//记录结果行数
int res = 0;
while(!queue.isEmpty()) {
//走一遍while就多遍历一行,res就++
res++;
int len = queue.size();
for(int i = 0; i < len; i++) {
TreeNode temp = queue.poll();
//当一个节点没有左右子节点时,直接返回结果,结束循环即可。
if(temp.left == null && temp.right == null) {
return res;
}
if(temp.left != null) {
queue.offer(temp.left);
}
if(temp.right != null) {
queue.offer(temp.right);
}
}
}
return res;
}
}
226. 翻转二叉树
- 226. 翻转二叉树 | 题目链接
- 代码随想录 | 讲解链接
- 题意:给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。
- 思路:递归三部曲
- 确定递归函数的参数(root)和返回值(TreeNode)
- 确定终止条件:当前节点为null时就返回
- 确定单层递归的逻辑
前序或后序遍历,中左右 / 左右中
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public TreeNode invertTree(TreeNode root) {
if(root == null) {
return null;
}
//后序遍历
invertTree(root.left);
invertTree(root.right);
swap(root);
return root;
}
//交换左右孩子
public void swap(TreeNode root) {
TreeNode temp = root.left;
root.left = root.right;
root.right = temp;
}
}
101.对称二叉树
- 101.对称二叉树 | 题目链接
- 代码随想录 | 讲解链接
- 题意:给你一个二叉树的根节点 root , 检查它是否轴对称。
- 思路:
- 判断根节点的左右子树是否对称,参数就是左子树节点和右子树节点。返回值布尔类型
- 确定终止条件:比较两个节点的数值是否相同,先判断两个节点空的情况。
左为空,右不为空,不对称
左不为空,右为空,不对称
左右都为空,对称
左右都不为空,比较节点的数值,不相同就false; - 剩下的最后一种情况就是,左右都不为空,且左右节点的数值相同,此时处理逻辑
- 处理单层递归的逻辑
比较二叉树外侧是否对称,判断左节点左孩子,右节点的右孩子
比较内测是否对称,判断左节点的右孩子,右节点的左孩子
如果左右都对称,那就返回true。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public boolean isSymmetric(TreeNode root) {
//直接传入根节点的左右孩子,判断左右两棵树是否对称
return leftrightIsSample(root.left, root.right);
}
public boolean leftrightIsSample(TreeNode left, TreeNode right) {
//排除空节点的情况
if(left == null && right == null) {
return true;
} else if(left == null && right != null) {
return false;
} else if(left != null && right == null) {
return false;
//排除了空节点,再排除数值不相同的情况
} else if(left.val != right.val) {
return false;
}
//此时是,左右节点都不为空,且数值相同的情况
//此时才递归,做下一层的判断
//左子树:左,右子树:右
boolean compareOutside = leftrightIsSample(left.left, right.right);
//左子树:右,右子树:左
boolean compareInside = leftrightIsSample(left.right, right.left);
//左子树:中,右子树:中,处理逻辑。左右都相等了,中间节点下的左右子树就是对称的
return compareOutside && compareInside;
}
}