代码随想录算法训练营(JAVA)| 第六章 二叉树part03

本文详细探讨了如何使用递归和迭代方法解决二叉树、N叉树的最大深度问题,以及如何计算完全二叉树的节点个数,涉及到了层序遍历和递归终止条件的运用。

      今日任务 

力扣 104. 二叉树的最大深度,   559. N 叉树的最大深度,  111. 二叉树的最小深度,  222. 完全二叉树的节点个数

递归法

  1. 确定递归函数的参数和返回值
  2. 确定终止条件
  3. 确定单层递归的逻辑

迭代法:

        使用层序遍历是最为合适的,因为最大的深度就是二叉树的层数,和层序遍历的方式极其吻合。


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

思路

题解

1.递归

本题可以使用前序(中左右),也可以使用后序遍历(左右中),使用前序求的就是深度,使用后序求的是高度。

  • 二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数或者节点数(取决于深度从0开始还是从1开始)
  • 二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数或者节点数(取决于高度从0开始还是从1开始)

而根节点的高度就是二叉树的最大深度,所以本题中我们通过后序求的根节点高度来求的二叉树最大深度。

class solution {
    /**
     * 递归法
     */
    public int maxDepth(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int leftDepth = maxDepth(root.left);
        int rightDepth = maxDepth(root.right);
        return Math.max(leftDepth, rightDepth) + 1;
    }
}

// 简化版写法
class Solution {
    public int maxDepth(TreeNode root) {
        if (root == null) return 0;

        return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
    }
}
2.迭代法,层序遍历
class Solution {
    public int maxDepth(TreeNode root) {
        if (root == null) return 0;

        Deque<TreeNode> deque = new LinkedList<>();
        deque.offer(root);
        int depth = 0;

        while (!deque.isEmpty()) {                
            int size = deque.size();
            depth++;

            for (int i = 0; i < size; i++ ) {
                TreeNode tmp = deque.poll();
                if (tmp.left != null) {
                    deque.offer(tmp.left);
                }
                if (tmp.right != null) {
                    deque.offer(tmp.right);
                }
            }
        }
        return depth;
    }
}

题目 :559. N 叉树的最大深度

思路

  同上题,子树遍历细节略有不同

题解

1.递归
class Solution {
    public int maxDepth(Node root) {
        if (root == null) return 0;
        int depth = 0;
        if (root.children != null) {
            for (Node child : root.children) {
                depth = Math.max(depth, maxDepth(child));
            }
        }
        return depth + 1;
    }
}
2.迭代法,层序遍历 + 队列
class Solution {
    public int maxDepth(Node root) {
        if (root == null) return 0;
        Deque<Node> deque = new LinkedList<>();
        deque.offer(root);
        int depth = 0;
        while (!deque.isEmpty()) {
            depth++;

            int len = deque.size();
            while (len-- > 0) {
                Node tmp = deque.poll();
                for (int i = 0; i < tmp.children.size(); i++ ) {
                    if (tmp.children.get(i) != null) {
                        deque.offer(tmp.children.get(i));
                    }
                }
            }
        }
        return depth;
    }
}

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

思路

有一个坑:最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

什么是叶子节点,左右孩子都为空的节点才是叶子节点!

如果这么求的话,没有左孩子的分支会算为最短深度,但!这是不对的

所以,如果左子树为空,右子树不为空,说明最小深度是 1 + 右子树的深度。

反之,右子树为空,左子树不为空,最小深度是 1 + 左子树的深度。 最后如果左右子树都不为空,返回左右子树深度最小值 + 1 。

题解 

1.递归法

相比求MaxDepth要复杂点,因为最小深度是从根节点到最近叶子节点的最短路径上的节点数量

class Solution {
    public String reverseWords(String s) {
        // 1.去除 前 中 后 空格
        StringBuilder sb = reverseSpace(s);
        // 2.整体反转
        reverseString(sb, 0, sb.length() - 1);
        // 3.单词反转
        reverseEachWorld(sb);

        return sb.toString();
    }
    
    private StringBuilder  reverseSpace(String s){
        int start = 0;
        int end = s.length() - 1;
        while (s.charAt(start) == ' ') start++;
        while (s.charAt(end) == ' ') end--;
        StringBuilder sb = new StringBuilder();
        while (start <= end) {
            char c = s.charAt(start);
            if (c != ' ' || sb.charAt(sb.length() - 1) != ' ') {
                sb.append(c);
            }
            start++;
        }
        return sb;
    }

    private void  reverseString(StringBuilder sb, int start, int end) {
        while (start < end) {

            char tmp = sb.charAt(start);
            sb.setCharAt(start, sb.charAt(end));
            sb.setCharAt(end, tmp);
            start++;end--;
        }
    }

    private void reverseEachWorld(StringBuilder sb) {
        int start = 0;
        int end = 1;
        int n = sb.length();
        while (start < n) {
            while (end < n && sb.charAt(end) != ' ') {
                end++;
            }
            reverseString(sb, start, end - 1);
            start = end + 1;
            end = start + 1;
        }
    }
}
2.递归法(思路来自二叉树最大深度的递归法)


该题求最小深度,最小深度为根节点到叶子节点的深度,所以在迭代到每个叶子节点时更新最小值。

class Solution {
    int depth = 0;
    int minDepth = Integer.MAX_VALUE;
    public int minDepth(TreeNode root) {
        dep(root);
        return minDepth == Integer.MAX_VALUE ? 0 : minDepth;
    }

    public void dep(TreeNode node) {
        if (node == null) return ;
        depth++;
        dep(node.left);
        dep(node.right);
        if (node.left == null && node.right == null) {
            minDepth = Math.min(minDepth, depth);
        }
        depth--;
    }
}
3.迭代法,层序遍历

需要注意的是,只有当左右孩子都为空的时候,才说明遍历到最低点了。如果其中一个孩子不为空则不是最低点

class Solution {
    public int minDepth(TreeNode root) {
        if (root == null) return 0;
        Deque<TreeNode> deque = new LinkedList<>();
        deque.offer(root);
        int depth = 0;
        while (!deque.isEmpty()) {
            int size = deque.size();
            depth++;
            for (int i = 0; i < size; i++ ) {
                TreeNode tmp = deque.poll();
                if (tmp.left == null && tmp.right == null) {
                    return depth;
                }
                if (tmp.left != null) deque.offer(tmp.left);
                if (tmp.right != null) deque.offer(tmp.right);
            }
        }
        return depth;
    }
}

题目 :222. 完全二叉树的节点个数

思路

在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2^(h-1)  个节点。

完全二叉树只有两种情况,情况一:就是满二叉树,情况二:最后一层叶子节点没有满。

对于情况一,可以直接用 2^树深度 - 1 来计算,注意这里根节点深度为1。

对于情况二,分别递归左孩子,和右孩子,递归到某一深度一定会有左孩子或者右孩子为满二叉树,然后依然可以按照情况1来计算。

题解

1.递归
class Solution {
    public int countNodes(TreeNode root) {
        if (root == null) return 0;
        return countNodes(root.left) + countNodes(root.right) + 1;
    }
}
2.递归
针对完全二叉树的解法

满二叉树的结点数为:2^depth - 1


首先,让我们理解代码中的两个while循环和接下来的if判断:

  1. 左子树深度计算 (while (left != null)):这个循环通过持续访问左子树的左孩子节点来计算左子树的深度。因为在一个完全二叉树中,如果我们一直沿着左边走到底,可以达到的深度是树的最大深度。

  2. 右子树深度计算 (while (right != null)):这个循环通过持续访问右子树的右孩子节点来计算右子树的深度。在一个完全二叉树中,如果右子树的深度与左子树的深度相同,那么这棵树是一棵满二叉树。

  3. 判断是否为满二叉树 (if (leftDepth == rightDepth)):如果左右子树的深度相同,那么根据完全二叉树的性质,这颗树是一棵满二叉树。此时,我们可以直接使用公式 (2^depth)−1 来计算节点数,这里使用的是位移操作 2 << leftDepth 来计算 2^(leftDepth + 1),然后再减去1来得到节点总数。

如果左右子树深度不同,则说明最底层不是完全填满的,我们需要递归地计算左子树和右子树的节点数,再加上根节点本身,即 countNodes(root.left) + countNodes(root.right) + 1

class Solution {
    public int countNodes(TreeNode root) {
        if (root == null) return 0;
        TreeNode left = root.left;
        TreeNode right = root.right;
        int leftDepth = 0, rightDepth = 0;
        while (left != null) {
            left = left.left;
            leftDepth++;
        }
        while (right != null) {
            right = right.right;
            rightDepth++;
        }
        if (leftDepth == rightDepth) {
            return (2 << leftDepth) - 1;
        }
        return countNodes(root.left) + countNodes(root.right) + 1;
    }
}
3.迭代法
class Solution {
    public int countNodes(TreeNode root) {
        if (root == null) return 0;
        Queue<TreeNode> que = new LinkedList<>();
        que.offer(root);
        int result = 0;
        while (!que.isEmpty()) {
            int size = que.size();
            while (size-- > 0) {
                TreeNode tmp = que.poll();
                result++;
                if (tmp.left != null) que.offer(tmp.left);
                if (tmp.right != null) que.offer(tmp.right);
            }
        }
        return result;
    }
}

代码随想录算法训练营是一个优质的学习和讨论平台,提供了丰富的算法训练内容和讨论交流机会。在训练营中,学员们可以通过观看视频讲解来学习算法知识,并根据讲解内容进行刷题练习。此外,训练营还提供了刷题建议,例如先看视频、了解自己所使用的编程语言、使用日志等方法来提高刷题效果和语言掌握程度。 训练营中的讨论内容非常丰富,涵盖了各种算法知识点和解题方法。例如,在第14天的训练营中,讲解了二叉树的理论基础、递归遍历、迭代遍历和统一遍历的内容。此外,在讨论中还分享了相关的博客文章和配图,帮助学员更好地理解和掌握二叉树的遍历方法。 训练营还提供了每日的讨论知识点,例如在第15天的讨论中,介绍了层序遍历的方法和使用队列来模拟一层一层遍历的效果。在第16天的讨论中,重点讨论了如何进行调试(debug)的方法,认为掌握调试技巧可以帮助学员更好地解决问题和写出正确的算法代码。 总之,代码随想录算法训练营是一个提供优质学习和讨论环境的平台,可以帮助学员系统地学习算法知识,并提供了丰富的讨论内容和刷题建议来提高算法编程能力。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [代码随想录算法训练营每日精华](https://blog.youkuaiyun.com/weixin_38556197/article/details/128462133)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值