小王的Java刷题日记Day7
记录刷题过程,作为笔记和分享,坚持每天刷题,每天进步,编程语言为Java。
题目一:二叉树的中序遍历
给定一个二叉树的根节点 root
,返回 它的 中序 遍历 。
例如:输入:root = [1,null,2,3]
输出:[1,3,2]
思路一:递归 (简单) 时间复杂度O(n)
1、按照访问左子树——根节点——右子树的方式遍历这棵树,而在访问左子树或者右子树的时候我们按照同样的方式遍历,直到遍历完整棵树。
2、递归实现
/** 二叉树的定义
* 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> inorderTraversal(TreeNode root) {
List<Integer>res=new ArrayList<Integer>();
dfs(res,root);
return res;
}
void dfs(List<Integer>res,TreeNode root){
if(root==null){ // 当前节点为空,直接返回
return;
}
dfs(res,root.left); // 递归遍历左子树
res.add(root.val); // 将当前节点的值添加到结果列表
dfs(res,root.right); // 递归遍历右子树
}
}
思路二:迭代法 (较难) 时间复杂度O(n)
1、递归实现时,是函数自己调用自己,一层层的嵌套下去,操作系统/虚拟机自动帮我们用 栈 来保存了每个调用的函数,现在我们需要自己模拟这样的调用过程。
2、递归的调用过程是不断往左边走,当左边走不下去了,就打印节点,并转向右边,然后右边继续这个过程。我们在迭代实现时,就可以用栈来模拟上面的调用过程。
/** 二叉树的定义
* 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> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
Stack<TreeNode> stack = new Stack<TreeNode>();
while (stack.size() > 0 || root != null) {
// 不断往左子树方向走,每走一次就将当前节点保存到栈中
// 这是模拟递归的调用
if (root != null) {
stack.add(root); // 将当前节点保存到栈中
root = root.left; // 继续往左子树方向走
} else {
// 当前节点为空,说明左边走到头了,从栈中弹出节点并保存
// 然后转向右边节点,继续上面整个过程
TreeNode tmp = stack.pop(); // 从栈中弹出节点
res.add(tmp.val); // 将弹出节点的值保存到结果列表中
root = tmp.right; // 转向右边节点
}
}
return res;
}
}
题目二:二叉树的最大深度
给定一个二叉树 root
,返回其最大深度。二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。
例如:输入:root = [3,9,20,null,null,15,7]
输出:3
思路一:后续遍历 时间复杂度O(n)
关键点: 此树的深度和其左(右)子树的深度之间的关系。显然,此树的深度 等于 左子树的深度 与 右子树的深度中的 最大值 +1 。
终止条件: 当 root 为空,说明已越过叶节点,因此返回 深度 000 。
递推工作: 本质上是对树做后序遍历。
1、计算节点 root 的 左子树的深度 ,即调用 maxDepth(root.left)。
2、计算节点 root 的 右子树的深度 ,即调用 maxDepth(root.right)。
返回值: 返回 此树的深度 ,即 max(maxDepth(root.left), maxDepth(root.right)) + 1。
/** 定义二叉树
* 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;
} else {
int leftHeight = maxDepth(root.left);
int rightHeight = maxDepth(root.right);
return Math.max(leftHeight, rightHeight) + 1;
}
}
}
思路二:层序遍历 时间复杂度O(n)
关键点: 每遍历一层,则计数器 +1 ,直到遍历完成,则可得到树的深度。
初始化: 队列 queue (加入根节点 root ),计数器 res = 0。
循环遍历: 当 queue 为空时跳出。
1、初始化一个空列表 tmp ,用于临时存储下一层节点。
2、遍历队列: 遍历 queue 中的各节点 node ,并将其左子节点和右子节点加入 tmp。
3、更新队列: 执行 queue = tmp ,将下一层节点赋值给 queue。
4、统计层数: 执行 res += 1 ,代表层数加 111。
返回值: 返回 res 即可。
/** 二叉树的定义
* 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;
List<TreeNode> queue = new LinkedList<>() {{ add(root); }}, tmp;
int res = 0;
while (!queue.isEmpty()) {
tmp = new LinkedList<>();
for(TreeNode node : queue) {
if (node.left != null) tmp.add(node.left);
if (node.right != null) tmp.add(node.right);
}
queue = tmp;
res++;
}
return res;
}
}