思考:优先掌握递归
迭代法有精力的可以去学习尝试
力扣题目 104.二叉树的最大深度
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) {
int result = 0;
if(root == null)
return result;
Deque<TreeNode> que = new LinkedList<>();
que.offer(root);
while(!que.isEmpty()){
int length = que.size();
while(length > 0){
TreeNode tempNode = que.poll();
if(tempNode.left != null)
que.offer(tempNode.left);
if(tempNode.right != null)
que.offer(tempNode.right);
length --;
}
result ++;
}
return result;
}
}
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 int maxDepth(TreeNode root) {
//第二步:确定终止的条件
if(root == null)
return 0;
//第三步:单层递归的逻辑
int leftDepth = maxDepth( root.left);
int rightDepth = maxDepth( root.right);
//因为每一次其实就是返回一个值“1”,+ 1是为相加起来
return Math.max(leftDepth,rightDepth) + 1;
}
}
力扣题目 559.N叉树的最大深度
/*
// 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 int maxDepth(Node root) {
int max = 0;
//第二步:终止的条件
if(root == null)
return 0;
//第三步:单次递归的逻辑
for(Node child : root.children){
max = Math.max(maxDepth(child),max);
}
return max + 1;
}
}
力扣题目 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;
}
//第三步:单层递归的逻辑
int leftDepth = minDepth(root.left); //左
int rightDepth = minDepth(root.right); //右
//左为空,右不为空,不是结果,继续往right遍历下去
if(root.left == null && root.right != null)
return 1+rightDepth;
//右为空,左不为空,不是结果,继续往left遍历下去
if(root.right == null && root.left != null)
return 1+leftDepth;
return Math.min(leftDepth,rightDepth) + 1;
}
}
力扣题目 222.完全二叉树的节点个数
tip:
题目提到的是完全二叉树,但是完全二叉树是由两种的:一、每一层节点数是达到最大的;二、除了最后一层节点数不是最大,其余的都是最大的节点数,而且最后一层的节点都是从左往右排序,不存在中的节点的左边是没有节点的。即完全二叉树不包括下面的情况:
结论
因此,可以对完全二叉树进行判断。
处于第一种情况的时候:可以直接用 2^树深度 - 1 来计算,注意这里根节点深度为1。
处于第二种情况的时候:分别递归左孩子,和右孩子,递归到某一深度一定会有左孩子或者右孩子为满二叉树,然后依然可以按照情况1来计算。
如果直接使用之前的后序遍历的公式,那个代码是直接遍历完整个二叉树,所以不存在说使用2^树深度 - 1来计算 。所以想用这个办法,需要另外直接用循环,直接从最左列和最右列遍历出去,判断两者是否相等。
补充的小知识:
java中没有2进制的数据类型,对二进制的操作,需要使用共三种操作符。
<< 左移位操作符
>> 右移位操作符
>>> 无符号右移操作符
使用左移时,数会变大,很多时间,用来代替“乘方”的操作。比如
2的平方 = 2 * 2 = 4 = 2<<1
2的3次方 = 2 * 2 * 2 = 8 = 2<<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 int countNodes(TreeNode root) {
//递归第二步:确定递归的终止条件
if(root == null)
return 0;
//递归第三步:单层递归的逻辑
int leftDepth = countNodes(root.left);
int rightDepth = countNodes(root.right);
//已经全部遍历完,所以直接左右相加,并且加头节点
return (leftDepth + rightDepth + 1);
}
}
小小总结
其实二叉树远远不止这些,还有很多。但是我先小小总结一下
(一)
迭代法中究竟什么时候用队列,什么时候用栈?
如果是模拟前中后序遍历就用栈,如果是适合层序遍历就用队列,当然还是其他情况,那么就是 先用队列试试行不行,不行就用栈。
(二)
求二叉树的各种最值,就想应该采用什么样的遍历顺序,确定了遍历循序,其实就和数组求最值一样容易了。
(三)
一般情况下:如果需要搜索整棵二叉树,那么递归函数就不要返回值,如果要搜索其中一条符合条件的路径,递归函数就需要返回值,因为遇到符合条件的路径了就要及时返回。
特别是有些时候 递归函数的返回值是bool类型,一些同学会疑惑为啥要加这个,其实就是为了找到一条边立刻返回。
其实还有一种就是后序遍历需要根据左右递归的返回值推出中间节点的状态,这种需要有返回值