题目一:二叉树的中序遍历(No. 948)
94. 二叉树的中序遍历 - 力扣(LeetCode)
题目难度:简单
给定一个二叉树的根节点 root
,返回 它的 中序 遍历 。
示例 1:
输入:root = [1,null,2,3]
输出:[1,3,2]
示例 2:
输入:root = []
输出:[]
示例 3:
输入:root = [1]
输出:[1]
提示:
- 树中节点数目在范围
[0, 100]
内 100 <= Node.val <= 100
题解
方法一:递归解法
所谓中序遍历就是按照这个顺序去遍历处理一个**节点,**即 左子树、节点、右子树这样的方式,所以对于一个节点的处理方式就是这样的:
- 遍历它的左子树、记录节点的值、遍历它的右子树
对每个节点都要进行上述的操作,而递归解法就可以实现这样的效果,只需要将上面的逻辑想清楚,剩下的交给递归去做就可以了。
class Solution {
List<Integer> res = new ArrayList<>();
public List<Integer> inorderTraversal(TreeNode root) {
reversal(root);
return res;
}
public void reversal(TreeNode node) {
if (node == null) return;
reversal(node.left); // 遍历左子树
res.add(node.val); // 记录节点的值
reversal(node.right); // 遍历右子树
}
}
方法二:迭代法
迭代法和递归是等价的,只是将迭代法隐式维护的栈显示的表现出来。
对于一个节点需要进行的操作就是:遍历左子树、输出本节点、遍历右子树;执行的逻辑就是,从根节点开始一直 将所有左节点压入栈,当到达底部,也就是节点为 null 的情况
此时栈中的数据为 [ 1 2 ], 然后将节点 2 从栈中弹出并存储结果,(此时对于 2 节点来说完成的操作就是:遍历左子树和输出本节点)
然后 去遍历节点的右节点,对于这个右节点,要执行的操作和上面相同,继续执行完成上面的逻辑;然后当右节点也遍历完之后,对于 1 节点,它的左子树就遍历完成了,将 1 节点弹出然后去遍历它的右节点,发现为空,结束遍历。
看下面的动图更加直观一些,为了更好的展示迭代的条件,这里多加了一个节点
class Solution {
List<Integer> res = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
public List<Integer> inorderTraversal(TreeNode root) {
// 上面弹出 1 的情况,栈为空但是节点不为空,还需要检测右节点的值
while (root != null || !stack.isEmpty()) {
while (root != null) {
stack.push(root);
root = root.left;
}
root = stack.pop();
res.add(root.val);
root = root.right;
}
return res;
}
}
题目二:二叉树的最大深度(No. 104)
104. 二叉树的最大深度 - 力扣(LeetCode)
题目难度:简单
给定一个二叉树 root
,返回其最大深度。
二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。
示例 1:
输入:root = [3,9,20,null,null,15,7]
输出:3
示例 2:
输入:root = [1,null,2]
输出:2
提示:
- 树中节点的数量在
[0, 104]
区间内。 100 <= Node.val <= 100
题解
对于一个路径来说,其最大的深度就是遍历到叶子节点的时候,所以本题的思路其实很容易想出,就是遍历所有的路径,当抵达叶子节点的时候记录一个值,在其中取一个最大的就是最终需要的结果。
本题的第一个思路就是,使用一个变量 depth 来记录当前节点的深度,一个变量 res 来存储目前的最大深度,当发现 node == null 的时候(说明可能抵达了叶子节点),与 res 做比较取一个最大值,当结束二叉树的遍历的时候,将结果返回。
class Solution {
int length = 0;
int res = 0;
public int maxDepth(TreeNode root) {
if (root == null) return 0;
reversal(root);
return res;
}
public void reversal(TreeNode node) {
if (node == null) {
res = Math.max(res, length);
return;
};
length++;
reversal(node.left);
reversal(node.right);
length--;
}
}
除了这种方法,其实可以在递归中去使用返回值,将一层递归中的返回值定义为:以这个节点为根节点的二叉树的最大深度,然后可以写出这样的代码:
class Solution {
public int maxDepth(TreeNode root) {
return reversal(root);
}
public int reversal(TreeNode node) {
if (node == null) {
return 0;
};
int leftDep = reversal(node.left);
int rightDep = reversal(node.right);
return Math.max(leftDep, rightDep) + 1; // 选取最大值作为本层的深度
}
}
题目三:翻转二叉树(No. 226)
226. 翻转二叉树 - 力扣(LeetCode)
题目难度:简单
给你一棵二叉树的根节点 root
,翻转这棵二叉树,并返回其根节点。
示例 1:
输入:root = [4,2,7,1,3,6,9]
输出:[4,7,2,9,6,3,1]
示例 2:
输入:root = [2,1,3]
输出:[2,3,1]
示例 3:
输入:root = []
输出:[]
提示:
- 树中节点数目范围在
[0, 100]
内 100 <= Node.val <= 100
题解
题目中要求的翻转二叉树,就是使每个节点的左子树和右子树交换,从叶子节点开始不断向上递归,最终就可以达到翻转整个二叉树的目的。
class Solution {
public TreeNode invertTree(TreeNode root) {
reverse(root);
return root;
}
public void reverse(TreeNode node) {
if (node == null) return;
TreeNode left = node.left;
TreeNode right = node.right;
// 交换左右节点
node.left = right;
node.right = left;
reverse(node.left);
reverse(node.right);
}
}
题目四:对称二叉树
101. 对称二叉树 - 力扣(LeetCode)
题目难度:简单
给你一个二叉树的根节点 root
, 检查它是否轴对称。
示例 1:
输入:root = [1,2,2,3,4,4,3]
输出:true
示例 2:
输入:root = [1,2,2,null,3,null,3]
输出:false
提示:
- 树中节点数目在范围
[1, 1000]
内 100 <= Node.val <= 100
题解
判断一个二叉树是否是对称二叉树,也就是判断左子树和右子树是否是对称的,这就需要镜像的遍历根节点的左子树和右子树,并在遍历的过程中不断的去比较两个节点是否相同。
用 left 表示左子树中的节点,用 right 表示右子树中的节点,镜像的去遍历和比较
- 比较 left 的左节点和 right 的右节点
- 比较 left 的右节点和 right 的左节点
通过上面两个步骤就实现了对于左子树和右子树镜像遍历,本题中需要收集结果,所以采用后序遍历的方式,将两个子树的结果进行与运算,作为本节点的结果返回。
class Solution {
public boolean isSymmetric(TreeNode root) {
if (root == null) return true;
return reversal(root.left, root.right);
}
public boolean reversal(TreeNode left, TreeNode right) {
// 判断
if (left != null && right == null) return false;
if (left == null && right != null) return false;
if (left == null && right == null) return true;
if (left.val != right.val) return false;
// 镜像遍历左右子树
boolean res1 = reversal(left.left, right.right);
boolean res2 = reversal(left.right, right.left);
// 后序收集结果
return res1 && res2;
}
}
题目五:二叉树的直径(No. 543)
543. 二叉树的直径 - 力扣(LeetCode)
题目难度:简单
给定一个二叉树 root
,返回其最大深度。
二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。
示例 1:
输入:root = [3,9,20,null,null,15,7]
输出:3
示例 2:
输入:root = [1,null,2]
输出:2
提示:
- 树中节点的数量在
[0, 104]
区间内。 100 <= Node.val <= 100
题解
对于一个节点来说,经过这个节点的最大路径就是从这个节点到左子树最深节点的距离加上从这个叶子节点到右子树最深叶子节点的距离。
本题的思路就是在递归的过程中去计算每个节点的最大路径,然后不断的去收集和比较,当递归遍历完所有的节点之后,得到的结果就是最终的结果。
一个节点到其左边最深节点的距离就是它左子节点到最深节点的距离
同理,右边的最大距离就是右子节点到最深节点的距离
res = Math.max(res, leftDep + rightDep);
将这两个值相加,得到的结果就是经过这个节点的最大深度,同时要将本节点到叶子节点的最大距离返回给上一个节点用作计算。
return Math.max(leftDep, rightDep) + 1;
写出代码
class Solution {
int depth = 0; // 深度,从叶子节点开始统计
int res = 0; // 最终的结果
public int diameterOfBinaryTree(TreeNode root) {
if (root == null) return 0;
getMaxDep(root);
return res;
}
public int getMaxDep(TreeNode node) {
if (node == null) {
return 0;
}
int leftDep = getMaxDep(node.left);
int rightDep = getMaxDep(node.right);
res = Math.max(res, leftDep + rightDep); // 计算经过本节点的最大深度
return Math.max(leftDep, rightDep) + 1;
}
}