Day 14 二叉树part 02
226. 翻转二叉树
private static TreeNode invertTree(TreeNode root) {
invert(root);
return root;
}
private static void invert(TreeNode root) {
if (root == null) return;
swap(root);
invert(root.left);
invert(root.right);
}
private static void swap(TreeNode root) {
TreeNode temp = root.left;
root.left = root.right;
root.right = temp;
}
交换的语法点
递归中要再最后设置return(若此方法要求返回值时)
public void swap(TreeNode root){
TreeNode temp=root.left;
root.left=root.right;
root.right=temp;
}
这里其实是很关键的一点 我本来方法参数设置为两个一个是root.left 另外一个是 root.right left和right其实是root中的成员变量 在方法中交换的只是对象副本,若要交换地址,可以直接传入root 然后在方法内直接root调用两个成员变量做交换
中序不行
前序和后序就调整一下,“中”操作的位置即可
若中序遍历代码直接移用,会有些问题,但是可以调整,它是先换左孩子,然后左右孩子互换,然后再换右孩子,这样"左"变到”右“,之后再换,也就是“左”(原来的左孩子)被换了两次,这样就只换了根节点的直接左右子树。
进入左,退出翻转左右子树,而后再进入左
private static TreeNode invertTree(TreeNode root) {
invert(root);
return root;
}
private static void invert(TreeNode root) {
if (root == null) return;
invert(root.left);
swap(root);
invert(root.left);//中序遍历,修改这个位置
}
private static void swap(TreeNode root) {
TreeNode temp = root.left;
root.left = root.right;
root.right = temp;
}
层序遍历
我们遇到一个节点,就交换这个节点的左右子树
private static TreeNode invertTree(TreeNode root) {
if (root == null) return null;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
int len = queue.size();
while (len-- > 0) {
TreeNode node = queue.poll();
swap(node);
if (node.left != null) queue.offer(node.left);
if (node.right != null) queue.offer(node.right);
}
}
return root;
}
private static void swap(TreeNode node) {
TreeNode temp = node.left;
node.left = node.right;
node.right = temp;
}
101. 对称二叉树
**这是左右子树(根节点的左右子树)的比较而不是左右孩子节点的比较 **两颗树相隔甚远还是可以当作左右孩子看待
一般收集左右孩子的信息并且向上返回,就要使用后序遍历
只要一个地方不愿意,递归的return会将false值返回 最后总返回结果被影响。
传入后compare左和右比时候 为空 不为空 ,不为空 为空,两边都为空,都不为空时值不相同的返回值。
这里需要先判断root是否为空,不判断,后面获取左右子树,可能会访问空指针。
public boolean isSymmetric(TreeNode root) {
if (root == null) return true;
return compare(root.left, root.right);
}
如何判断左右子树可以相互翻转,外和外比、内和内比?
判断之后,传入外侧的节点和内侧节点
boolean outside = compare(left.left, right.right);// 左子树:左、 右子树:右
boolean inside = compare(left.right, right.left);// 左子树:右、 右子树:左
return outside && inside;// 左子树:中、 右子树:中(逻辑处理)
public boolean isSymmetric(TreeNode root) {
if (root == null) return true;
return compare(root.left, root.right);
}
private static boolean compare(TreeNode left, TreeNode right) {
if (left == null && right != null) {
return false;
} else if (left != null && right == null) {
return false;
} else if (left == null && right == null) {
return true;
} else if (left.val != right.val) {
return false;
}
boolean outside = compare(left.left, right.right);// 左子树:左、 右子树:右
boolean inside = compare(left.right, right.left);// 左子树:右、 右子树:左
return outside && inside;// 左子树:中、 右子树:中(逻辑处理)
}
104. 二叉树的最大深度
根节点的高度就算该二叉树的最大深度
递归遍历时,后序遍历求高度,父节点取左右子树的高度相加;而前序遍历求的是深度,但是这里恰好是最大深度。
层序遍历
private static int maxDepth(TreeNode root) {
if (root == null) return 0;
Queue<TreeNode> queue = new LinkedList<>();
int max = 0;
queue.offer(root);
while (!queue.isEmpty()) {
int len = queue.size();
max++;//一层+1
while (len-- > 0) {
TreeNode node = queue.poll();
if (node.left != null) queue.offer(node.left);
if (node.right != null) queue.offer(node.right);
}
}
return max;
}
递归遍历
递归三部曲:
- 参数和返回值
- 结束条件
- 执行单层递归逻辑
若为空节点就返回高度为0,先求它的左子树的深度,再求右子树的深度,最后取左右深度最大的数值 **再+1 (加1是因为算上当前中间节点)**就是目前节点为根节点的树的深度。不加一则返回0,因为它+1是算上本节点。
111. 二叉树的最小深度
注意定义: 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
判断不为空,是防0,这样min就不会一直取0
递归
private static int minDepth(TreeNode root) {
if (root == null) return 0;
int leftMin = minDepth(root.left);
int rightMin = minDepth(root.right);
//由于最小深度是从根节点到最近叶子节点的最短路径上的节点数量
//这有坑,返回最小值,如果根节点的一个子树为空,它会把左子树返回的0给算入,这样就不是 叶子节点
if (root.left == null && root.right != null) {
return rightMin + 1;
}
if (root.left != null && root.right == null) {
return leftMin + 1;
}
return Math.min(leftMin, rightMin) + 1; //需要每层+1
}
层序
这里求的是最小深度,就是求我们的,如果结点中有左右两孩子都为null则到达了(取到叶子节点了),若只有一个为null则要继续往下
如果左或者右结点为空 我们返回另外一个不为空结点的高度+1,因为此刻是将左右子树的正确的高度做出一个汇总,要加上root结点本身的高度
break;return minDepth;这里应该是直接返回,而不是break打断。
public int minDepth(TreeNode root) {
if (root == null) return 0;
int minDepth = 0;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
int len = queue.size();
minDepth++;
while (len-- > 0) {
TreeNode node = queue.poll();
if (node.left == null && node.right == null) return minDepth;
if (node.left != null) queue.offer(node.left);
if (node.right != null) queue.offer(node.right);
}
}
return minDepth;
}
错误点
if (node.left != null && node.right == null) queue.offer(node.left);
if (node.left == null && node.right != null) queue.offer(node.right);
这个应该改为如下
if (node.left != null ) queue.offer(node.left);
if (node.right != null) queue.offer(node.right);
如果一个节点同时存在左右子节点(例如根节点既有左子树又有右子树),则两个子节点都不会被加入队列。