算法从0到1 Day 14 二叉树part 02

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;
    }

递归遍历

递归三部曲:

  1. 参数和返回值
  2. 结束条件
  3. 执行单层递归逻辑

若为空节点就返回高度为0,先求它的左子树的深度,再求右子树的深度,最后取左右深度最大的数值 **再+1 (加1是因为算上当前中间节点)**就是目前节点为根节点的树的深度。不加一则返回0,因为它+1是算上本节点。

111. 二叉树的最小深度

image-20250520142533097

注意定义: 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

判断不为空,是防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);

如果一个节点同时存在左右子节点(例如根节点既有左子树又有右子树),则两个子节点都不会被加入队列。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值