目录
226.翻转二叉树
翻转一下,前序后序都行---前序就是先把上面的翻了再翻下面的,后续就是从下往上翻
错误示范
public TreeNode invertTree(TreeNode root) {
//深度
if (root == null) return root;
swap(root.left, root.right);
invertTree(root.left);
invertTree(root.right);
return root;
}
public void swap(TreeNode left, TreeNode right) {
TreeNode temp = left;
left = right;
right = temp;
在上述代码中,left 和 right 是局部变量,它们的改变不会影响调用 swap 方法时传入的实际参数(即 root.left 和 root.right)。我们需要理解的是,Java 方法参数是按值传递的,对于对象参数,传递的是对象引用的拷贝,而不是引用本身。你这样传的是指针的拷贝。
正确
public TreeNode invertTree(TreeNode root) {
//深度
if (root == null) return root;
//交换
TreeNode temp = root.left;
root.left = root.right;
root.right = temp;
//递归
invertTree(root.left);
invertTree(root.right);
return root;
}
另外两种方法
- 层序遍历也可以做--队列poll的以后,把node的左右孩子换一下位置,然后再做判断进行存入
- 前序也可以--栈弹出的时候先交换,再push进右左节点
101. 对称二叉树
思路
- 只能后续遍历--所有需要孩子信息并像上一层返回的都是后续遍历
- 判断完外侧节点,再判断内侧节点,两个都相同就可以告诉他们父节点:你的孩子没问题啦
- 左子树左右中;右子树左右中
- 只能后续,你左右子孩子都没处理,你咋能上来想得到中的结果
- 本题遍历只能是“后序遍历”,因为我们要通过递归函数的返回值来判断两个子树的内侧节点和外侧节点是否相等。
递归写法
public boolean isSymmetric(TreeNode root) {
//递归:确定函数的参数和返回值
return compare(root.left, root.right);
}
public boolean compare(TreeNode left, TreeNode right) {
//4种可能性--结束条件
if (left == null && right == null) {
return true;
}
if (left == null || right == null || left.val != right.val) {
return false;
}
//单层递归逻辑--后序遍历-左子树左右中-右子树又做右左中,你不把孩子节点处理了,你怎么能处理中节点说下面的没问题了呢
compare(left.left, right.right);
compare(left.right, right.left);
return compare(left.left, right.right) && compare(left.right, right.left);
}
队列写法
通过队列来判断根节点的左子树和右子树的内侧和外侧是否相等
public boolean isSymmetric(TreeNode root) {
Queue<TreeNode> que = new LinkedList<>();
que.offer(root.left);
que.offer(root.right);
while (!que.isEmpty()) {
TreeNode leftNode = que.poll();
TreeNode rightNode = que.poll();
if (leftNode == null && rightNode == null) {
continue;
}
if (leftNode == null || rightNode == null || leftNode.val != rightNode.val) {
return false;
}
que.offer(leftNode.left);
que.offer(rightNode.right);
que.offer(leftNode.right);
que.offer(rightNode.left);
}
return true;
}
拓展类似题
100 两棵树是否相同
public boolean isSameTree(TreeNode p, TreeNode q) {
if (p == null && q == null) return true;
if (p == null || q == null || p.val != q.val) return false;
//后续遍历
return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
}
比较两棵树是否相等其实就是一棵树是否是反转树的变形
三种不符合的情况+后续遍历直接结束
572 一棵树是否是另外一棵的子树
public boolean isSubtree(TreeNode root, TreeNode subRoot) {
if (root == null) return false;
if (check(root, subRoot)) return true;
//开始比较
return isSubtree(root.left, subRoot) || isSubtree(root.right, subRoot);//这里要用并集,因为一个符合就行
}
// public TreeNode findRoot(TreeNode node, TreeNode subRoot) {
// if (node == null) return null;
// if (node == subRoot) return node;
// if (findRoot(node.left, subRoot) != null) return findRoot(node.left, subRoot);
// else return findRoot(node.right, subRoot);
// }
public boolean check (TreeNode root, TreeNode subRoot) {
if (root == null && subRoot == null) return true;
if (root == null || subRoot == null || root.val != subRoot.val) return false;
return check(root.left, subRoot.left) && check(root.right, subRoot.right);
}
和常规的相比多了一个遍历的过程 不需要去找对应的起点,直接主函数里递归一遍看看符不符合就行,不过要注意return的时候用并集,因为左右只要有一个满足就行
104.二叉树的最大深度
本题可以使用前序(中左右),也可以使用后序遍历(左右中),使用前序求的就是深度,使用后序求的是高度。
- 二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数或者节点数(取决于深度从0开始还是从1开始)
- 二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数或者节点数(取决于高度从0开始还是从1开始)
而根节点的高度就是二叉树的最大深度,所以本题中我们通过后序求的根节点高度来求的二叉树最大深度。(当然,本题也可以用层序遍历,见上一章)
public int maxDepth(TreeNode root) {
//找最大深度就是找树的高度---高度怎么求:高度是左右子树大的那个+1---
if (root == null) return 0;
int height1 = maxDepth(root.left);
int height2 = maxDepth(root.right);
return 1 + Math.max(height1, height2);
}
求高度---用后序遍历 求深度---用前序遍历
根节点的高度其实就是二叉树的最大深度
拓展--n叉树最大深度
思路一样,注意一点,n叉树要先将所有孩子节点取出,不能直接root.node
public int maxDepth(Node root) {
//最大高度
if (root == null) return 0;
int height = 0;
//因为Node只能.children,所以要先全取出来然后遍历
List<Node> children = root.children;
for (Node node : children) {
height = Math.max(maxDepth(node), height);
}
return height + 1;
}
111.二叉树的最小深度
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。注意是叶子节点。
什么是叶子节点,左右孩子都为空的节点才是叶子节点!
public int minDepth(TreeNode root) {
//最小深度就是离一个节点,这个节点没有左右子树的距离
if (root == null) return 0;
int height1 = minDepth(root.left);
int height2 = minDepth(root.right);
if (root.left == null) {
return height2 + 1;
}
if (root.right == null) {
return height1 + 1;
}
// 左右结点都不为null
return Math.min(height1, height2) + 1;
}
求二叉树的最小深度和求二叉树的最大深度的差别主要在于处理左右孩子不为空的逻辑。最小深度需要加入一边为空的时候的判断