二叉树经典题目226.翻转二叉树100.相同的树101.对称二叉树116.填充每个节点的下一个右侧节点指针104.二叉树最大深度111.二叉树最小深度671.二叉树中第二小的节点993.二叉树的堂兄弟节点
当前 root 节点 【该做什么】【什么时候做】
xxxxxxxxxx
// 该做什么:对于当前 root 节点,交换左右子树
// 什么时候做:先序遍历 || 后序遍历
public TreeNode invertTree(TreeNode root) {
if (root == null) return null;
// 先序遍历的处理阶段(交换左右子树)
TreeNode leftNode = root.left;
TreeNode rightNode = root.right;
root.left = rightNode;
root.right = leftNode;
// 递归处理左右子树
invertTree(leftNode);
invertTree(rightNode);
return root;
}
public TreeNode invertTree(TreeNode root) {
if (root == null) return null;
// 递归处理左右子树
TreeNode leftNode = invertTree(root.left);
TreeNode rightNode = invertTree(root.right);
// 后序遍历的处理阶段
root.left = rightNode;
root.right = leftNode;
return root;
}
xxxxxxxxxx
// 该做什么:对于当前 root 节点,判断是否相同(值相同)
// 什么时候做:先序遍历(先判断根是否相同,如果相同递归判断左右子树是否相同)
public boolean isSameTree(TreeNode p, TreeNode q) {
// 先序遍历的处理阶段
if (p == null || q == null) return p == q;
if (p.value != q.value) return false;
// 递归处理左右子树
return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
}
xxxxxxxxxx
// 该做什么:对于当前 root 节点,判断左右子树是否对称(需要增加参数)
// 什么时候做:先序遍历
/**
* 判断是否为对称二叉树
* @param root 根节点
* @return boolean
*/
public boolean isSymmetric(TreeNode root) {
if (root == null) return true;
return isSymmetricHelper(root.left, root.right);
}
/**
* 判断对称二叉树的帮助函数
* @param leftTree left tree
* @param rightTree right tree
* @return boolean
*/
public boolean isSymmetricHelper(TreeNode leftTree, TreeNode rightTree) {
// 先序遍历处理阶段
if (leftTree == null || rightTree == null) return leftTree == rightTree;
if (leftTree.value != rightTree.value) return false;
// 递归处理左右子树
return isSymmetricHelper(leftTree.left, rightTree.right) && isSymmetricHelper(leftTree.right, rightTree.left);
}
xxxxxxxxxx
// 该做什么:对于当前节点,把左节点的 next 指向 右节点(一个参数做不到 / 切记每次都只考虑当前节点,不要考虑孩子节点)
// 什么时候做:先序遍历
/**
* 填充每个节点的下一个右侧节点指针
* @param root 根节点
* @return root
*/
public Node connect(Node root) {
if (root == null) {
return null;
}
connectHelper(root.left, root.right);
return root;
}
/**
* 填充每个节点的下一个右侧节点指针 帮助函数
* @param leftTree left tree
* @param rightTree right tree
*/
public void connectHelper(Node leftTree, Node rightTree) {
// 先序遍历处理阶段
if (leftTree == null || rightTree == null) {
return;
}
leftTree.next = rightTree;
// 递归
connectHelper(leftTree.left, leftTree.right);
connectHelper(leftTree.right, rightTree.left);
connectHelper(rightTree.left, rightTree.right);
}
xxxxxxxxxx
// 该做什么:对于当前节点,如果为 null,则返回 0,表示深度为 0,如果非空则和深度更大的子树 +1
// 什么时候做:先序遍历
public int maxDepth(TreeNode root) {
// 先序遍历处理阶段
if (root == null) return 0;
// 递归,选择深度更大的子树
return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
}
xxxxxxxxxx
public int minDepth(TreeNode root) {
if (root == null) return 0;
// 不同之处:如果不加此判断,左右孩子有一个为 null 时,会选择为空的子孩子
if (root.left == null) return minDepth(root.right) + 1;
if (root.right == null) return minDepth(root.left) + 1;
return Math.min(minDepth(root.left), minDepth(root.right)) + 1;
}
xxxxxxxxxx
// 递归:分解子问题
// 当前节点:root
// 该做什么:如下
// 什么时候做:后序遍历
// 返回值:第二小节点值
// 前提:root 是最小节点
public int findSecondMinimumValue(TreeNode root) {
// 如果无孩子节点,则不存在第二小节点
if (root.left == null && root.right == null) return -1;
// 记录左右孩子值
int left = root.left.val;
int right = root.right.val;
// 如果 root 值等于左孩子值,则去左子树找
if (root.val == left) {
left = findSecondMinimumValue(root.left);
}
// 如果 root 值等于右孩子值,则去右子树找
if (root.val == right) {
right = findSecondMinimumValue(root.right);
}
// --------------- 处理过程 ---------------
// 如果左孩子没找到,则右孩子是第二小节点
if (left == -1) return right;
// 如果右孩子没找到,则左孩子是第二小节点
if (right == -1) return left;
// 如果左右孩子都找到了第二小值,则取两者最小值
return Math.min(left, right);
}
// 善于运用全局变量
TreeNode parentX = new TreeNode(-1);
TreeNode parentY = new TreeNode(-1);
int depthX = 0;
int depthY = 0;
int x;
int y;
public boolean isCousins(TreeNode root, int x, int y) {
this.x = x;
this.y = y;
traversal(root, null, 0);
if (depthX == depthY && parentX != parentY) return true;
return false;
}
private void traversal(TreeNode root, TreeNode parent, int depth) {
if (root == null) return ;
if (root.val == x) {
parentX = parent;
depthX = depth;
}
if (root.val == y) {
parentY = parent;
depthY = depth;
}
traversal(root.left, root, depth + 1);
traversal(root.right, root, depth + 1);
}