LeetCode226.反转二叉树/LeetCode101.对称二叉树/LeetCode104.二叉树的最大深度/LeetCode111.二叉树的最小深度

LeetCode226.反转二叉树/LeetCode101.对称二叉树/LeetCode104.二叉树的最大深度/LeetCode111.二叉树的最小深度_第1张图片

题目一:LeetCode226.反转二叉树

题目链接:226. 翻转二叉树 - 力扣(LeetCode)

LeetCode226.反转二叉树/LeetCode101.对称二叉树/LeetCode104.二叉树的最大深度/LeetCode111.二叉树的最小深度_第2张图片

 //递归法
// class Solution {
//     public TreeNode invertTree(TreeNode root) {
//         if(root == null){
//             return root;
//         }

//         TreeNode left = invertTree(root.left);
//         TreeNode right = invertTree(root.right);
//         root.left = right;
//         root.right = left;   
//         return root;  
//     }
// }

//BFS迭代
//层序遍历的类似题
class Solution {
    public TreeNode invertTree(TreeNode root) {
        if (root == null) {return null;}
        ArrayDeque deque = new ArrayDeque<>();
        deque.offer(root);
        while (!deque.isEmpty()) {
            int size = deque.size();
            while (size-- > 0) {
                TreeNode node = deque.poll();
                swap(node);
                if (node.left != null) deque.offer(node.left);
                if (node.right != null) deque.offer(node.right);
            }
        }
        return root;
    }
    public void swap(TreeNode root) {
        TreeNode temp = root.left;
        root.left = root.right;
        root.right = temp;
    }
}

 本题采用递归法和BFS(广度优先搜索)-迭代法两种解法;

重点在于如何交换左右子树;

要注意当第二层交换时,属于他们的第三层的子树也会随之交换。


题目二:LeetCode101.对称二叉树 

 题目链接:101. 对称二叉树 - 力扣(LeetCode)

 ​​​​​​LeetCode226.反转二叉树/LeetCode101.对称二叉树/LeetCode104.二叉树的最大深度/LeetCode111.二叉树的最小深度_第3张图片

class Solution {
    public boolean isSymmetric(TreeNode root) {
        return check(root.left, root.right);
    }

    public boolean check(TreeNode p, TreeNode q){
        if(p ==null && q == null){
            return true;
        }
        if(p == null || q == null){
            return false;
        }
        return p.val == q.val && check(p.left, q.right) && check(p.right, q.left);
    }
}

递归法主要是要构造一个可以验证对称的循环体;

这里要注意(p == null && q == null) 和 (p == null || q == null)特殊情况的判断,因为当为null,是无法通过 == 来比较的,就算一个有值,一个为空也是不可以比较的,会报错。


题目三:LeetCode104.二叉树的最大深度

 题目链接:104. 二叉树的最大深度 - 力扣(LeetCode)

 ​​​​​​LeetCode226.反转二叉树/LeetCode101.对称二叉树/LeetCode104.二叉树的最大深度/LeetCode111.二叉树的最小深度_第4张图片

 //层序遍历 && BFS
// class Solution {
//     public int maxDepth(TreeNode root) {
//         int max_depth = -1;

//         Queue nodeQueue = new LinkedList();
//         Queue depthQueue = new LinkedList();

//         nodeQueue.add(root);
//         depthQueue.add(0);
//         int depth = 0;

//         // while(nodeQueue != null){
//         //这种方法是不行的,因为nodeQueue != null只能检查队列本身是否为null
//         //但是队列一旦有值,哪怕又被移除,队列为空,但是这都不是队列为null
//         //如果这里使用while(nodeQueue != null){,则会造成无限循环
//         //这个条件只会在队列对象未被初始化(即 nodeQueue 从未被赋值)时为 false
//         //所以我们可以用这个条件检查是否一个节点都没有
//         while(!nodeQueue.isEmpty()){
//             //弹出队首节点
//             TreeNode node = nodeQueue.remove();
//             //弹出对应的深度值,因为我们在放入时,这两者是对应的
//              depth = depthQueue.remove();
//             if(node != null){
//                 //记录当前访问的的最大深度
//                 max_depth = Math.max(max_depth,depth);
                
//                 //先放入左节点,再放入右节点,这样根据队列队尾进,队首出,先进先出的规则
//                 //左节点先被加入节点队列,然后右节点才进入
//                 //因为两者的深度值一样,也就是depth一样,这样在map中
//                 //如果右节点有值,则右节点的值会覆盖掉左节点,保证右侧视角
//                 nodeQueue.add(node.left);
//                 nodeQueue.add(node.right);
//                 depthQueue.add(depth + 1);
//                 depthQueue.add(depth + 1);
//             }
//         }
//         return max_depth + 1;
//     }
// }



//DFS(深度优先搜索)
class Solution{
    public int maxDepth(TreeNode root){
        if(root == null){
            return 0;
        }else{
            int leftHeight = maxDepth(root.left);
            int rightHeight = maxDepth(root.right);
            return Math.max(leftHeight, rightHeight) + 1;
        }
    }
}

推荐使用递归的DFS,代码更加流畅更加简洁;

别忘了最后+1,因为 我们是从0开始计算的,这里是深度,所以必须加 1 。


 题目四:LeetCode111.二叉树的最小深度

题目链接:111. 二叉树的最小深度 - 力扣(LeetCode)

LeetCode226.反转二叉树/LeetCode101.对称二叉树/LeetCode104.二叉树的最大深度/LeetCode111.二叉树的最小深度_第5张图片

class Solution {
    public int minDepth(TreeNode root) {
        if (root == null) {
            return 0;
        }

        if (root.left == null && root.right == null) {
            return 1;
        }

        int min_depth = Integer.MAX_VALUE;
        if (root.left != null) {
            min_depth = Math.min(minDepth(root.left), min_depth);
        }
        if (root.right != null) {
            min_depth = Math.min(minDepth(root.right), min_depth);
        }

        return min_depth + 1;
    }
}

递归调用的完整流程

1. 从根节点 A 开始

  • 调用 minDepth(A)

    • A 不是空节点,也不是叶子节点。

    • 需要计算 A 的左右子树深度:

      • 左子树 B 的深度:minDepth(B)

      • 右子树 C 的深度:minDepth(C)

2. 计算左子树 B 的深度

  • 调用 minDepth(B)

    • B 不是空节点,也不是叶子节点(有左子节点 D)。

    • 计算 B 的左右子树深度:

      • 左子树 D 的深度:minDepth(D)

      • 右子树为空,跳过。

    • 调用 minDepth(D)

      • D 是叶子节点,直接返回 1

    • B 的 min_depth = min(1, ∞) = 1

    • 返回 1 + 1 = 2B 的深度)。

3. 回溯到 A,计算右子树 C 的深度

  • 调用 minDepth(C)

    • C 不是空节点,也不是叶子节点(有左右子节点 E 和 F)。

    • 计算 C 的左右子树深度:

      • 左子树 E 的深度:minDepth(E)

      • 右子树 F 的深度:minDepth(F)

4. 计算 C 的左子树 E 的深度

  • 调用 minDepth(E)

    • E 不是空节点,也不是叶子节点(有右子节点 G)。

    • 计算 E 的左右子树深度:

      • 左子树为空,跳过。

      • 右子树 G 的深度:minDepth(G)

    • 调用 minDepth(G)

      • G 是叶子节点,直接返回 1

    • E 的 min_depth = min(∞, 1) = 1

    • 返回 1 + 1 = 2E 的深度)。

5. 计算 C 的右子树 F 的深度

  • 调用 minDepth(F)

    • F 是叶子节点,直接返回 1

6. 完成 C 的深度计算

  • min_depth = min(2, 1) = 1(来自 E 和 F 的较小值)。

  • 返回 1 + 1 = 2C 的深度)。

7. 完成 A 的深度计算

  • min_depth = min(2, 2) = 2(来自 B 和 C 的较小值)。

  • 返回 2 + 1 = 3A 的深度)。

递归的本质

从根节点开始,先递归左子树,再递归右子树。

每次递归调用完成后,会返回到上一层调用。

你可能感兴趣的:(算法(LeetCode,代码随想录),数据结构,算法)