Leetcode 刷题日记
2021.2.14
题目链接:
https://leetcode-cn.com/problems/er-cha-shu-de-shen-du-lcof/submissions/
问题描述:
输入二叉树的根节点,返回其深度
解答1:
非递归深度优先搜索
代码:
public class Solution {
public int maxDepth(TreeNode root) {
if(root == null) return 0;
//若根节点为空,则深度为0,否则执行下面的代码
LinkedList<TreeNode> stack = new LinkedList<>();
stack.push(root);
int depth = 0;
while(!stack.isEmpty()){
TreeNode oldPeek = stack.peek();
if(oldPeek.left != null) {
stack.push(oldPeek.left);
oldPeek.left = null;
}
else if(oldPeek.right != null) {
stack.push(oldPeek.right);
oldPeek.right = null;
}
else{
depth = Math.max(depth, stack.size());
stack.pop();
}
}
return depth;
}
}
分析:
时间复杂度:O(n)
空间复杂度:O(n)
运行结果:
评注:
深度优先搜索的基本原理:
1.记号约定:从一个节点(记为F)第一次到达下一个节点(记为S),则把F标记为S的上一节点。
2.基本操作:
①若S即为搜索的目标,则返回S;
②否则,若从S还有通向其他节点(即,除F外的节点)的路径,则选择某一路径进入下一节点;
③否则,若从S只有通向F的路径,则返回到F,并把从F到S的路径擦除,然后判断是否有F通向其他节点(即,除F的上一节点外的节点)的路径,若有,则进入②,否则进入③。
深度优先搜索可以通过维护一个栈来实现:
1.首先,把根节点压入栈中,使栈顶节点不为null。
2.然后,构建循环
(1)若栈顶节点(设为P)有左孩子(左孩子域不为null),则将左孩子压入栈中,使左孩子成为新的栈顶,同时把P的左孩子域设为null。
(2)否则,若栈顶节点有右孩子(右孩子域不为null),则将右孩子压入栈中,使右孩子成为新的栈顶,同时把P的右孩子域设为null。
(3)否则,该节点必为叶子节点或其左右子树都被遍历过,此时栈的元素个数即为该节点的深度,记录深度后将其弹出。
所有记录的深度的最大值即为树的深度
题外话:这实际涉及到对树的遍历。树的遍历方式有两大类,一类是基于深度优先的先序、中序和后序遍历;另一类是基于广度优先的层次遍历。
前者可以使用栈来实现(如本解答),后者可以用队列来实现(如下一解答)。
解答2:
非递归广度优先搜索(层次遍历)
代码:
public class Solution {
public int maxDepth(TreeNode root) {
if(root == null) return 0;
int depth = 1;
LinkedList<TreeNode> queue = new LinkedList<>();
queue.addFirst(root);
while(!queue.isEmpty()){
int size = queue.size();
for (int i = 0; i < size; i++) {
TreeNode oldFirst = queue.removeFirst();
if(oldFirst.left != null) queue.addLast(oldFirst.left);
if(oldFirst.right != null) queue.addLast(oldFirst.right);
}
depth ++;
}
return depth;
}
}
分析:
时间复杂度:O(n)
空间复杂度:O(n)
运行结果:
评注:
与基于栈的深度优先搜索相对应,本题也可使用基于队列的广度优先搜索解答。具体思路可以类比深度优先。由于这里是一层一层地遍历,所以在while循环里面嵌套了一个for循环来对每一层的节点进行遍历。
解答3:
递归(本质是深度优先)
代码:
public class Solution {
public int maxDepth(TreeNode root) {
if(root == null) return 0;
else if(root.left == null && root.right == null) return 1;
else if(root.left != null && root.right == null) return maxDepth(root.left) + 1;
else if(root.left == null && root.right != null) return maxDepth(root.right) + 1;
else return Math.max(maxDepth(root.left),maxDepth(root.right)) + 1;
}
}
分析:
时间复杂度:O(n)
空间复杂度:O(n)
运行结果:
评注:
递归是最快的解答。虽然本题给出的三种解答的时间复杂度相同,但是由于递归所需要的操作少于前两种,并且由于本题数据量不大,调用方法所消耗的时间可以忽略,所以递归成为了最快的实现方式。