• 【LeetCode】104.二叉树的最大深度(递归+迭代,超详细解释)


    题目

    给定一个二叉树,找出其最大深度。

    二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

    说明: 叶子节点是指没有子节点的节点。

    示例:
    给定二叉树 [3,9,20,null,null,15,7],

    	3
       / 
      9  20
        /  
       15   7
    

    返回它的最大深度3.

    题解

    代码如下:

    	public int maxDpeth(TreeNode root){
    		if(root == null ) return 0;//输入的树为空,返回
    		int l_depth = maxDepth(root.left);//递归寻找左子树最大深度
    		int r_depth = maxDepth(root.right);//递归寻找右子树最大深度
    		return Math.max(l_depth,r_depth)+1;//返回最大深度,此处要加上根节点。
    	}
    

    题目分析

    这道题目可以运用递归解决树的方法,因为题目要求传递一个参数,所以我们可以采用“自底向上”的方法去解决本题。

    运用递归解决树的问题

    递归是解决树的相关问题最有效和最常用的方法之一。
    我们知道,树可以以递归的方式定义为一个节点(根节点),它包括一个值和一个指向其他节点指针的列表。 递归是树的特性之一。 因此,许多树问题可以通过递归的方式来解决。 对于每个递归层级,我们只能关注单个节点内的问题,并通过递归调用函数来解决其子节点问题。

    通常,我们能通过“自顶向上” 或 “自底向上的”递归来解决树的问题。

    "自顶向下"的解决方案


    自顶向下意味着在每个递归层级,我们将首先访问节点来计算一些值并在递归调用函数时将这些值传递到子节点。 所以 “自顶向下” 的解决方案可以被认为是一种前序遍历。 具体来说,递归函数 top_down(root, params) 的原理是这样的:

    1. return specific value for null node
    2. update the answer if needed                      // anwer <-- params
    3. left_ans = top_down(root.left, left_params)      // left_params <-- root.val, params
    4. right_ans = top_down(root.right, right_params)   // right_params <-- root.val, params
    5. return the answer if needed                      // answer <-- left_ans, right_ans
    

    例如,思考这样一个问题:给定一个二叉树,请寻找它的最大深度。
    我们知道根节点的深度是1。 对于每个节点,如果我们知道某节点的深度,那我们将知道它子节点的深度。 因此,在调用递归函数的时候,将节点的深度传递为一个参数,那么所有的节点都知道它们自身的深度。 而对于叶节点,我们可以通过更新深度从而获取最终答案。 这里是递归函数 maximum_depth(root, depth) 的伪代码:

    1. return if root is null
    2. if root is a leaf node:
    3.      answer = max(answer, depth)         // update the answer if needed
    4. maximum_depth(root.left, depth + 1)      // call the function recursively for left child
    5. maximum_depth(root.right, depth + 1)     // call the function recursively for right child
    

    以下提供Java的代码以供参考

    private int answer;		// don't forget to initialize answer before call maximum_depth
    private void maximum_depth(TreeNode root, int depth) {
        if (root == null) {
            return;
        }
        if (root.left == null && root.right == null) {
            answer = Math.max(answer, depth);
        }
        maximum_depth(root.left, depth + 1);
        maximum_depth(root.right, depth + 1);
    }
    

    “自底向上”的解决方案


    “自底向上” 是另一种递归方法。 在每个递归层次上,我们首先对所有子节点递归地调用函数,然后根据返回值和根节点本身的值得到答案。 这个过程可以看作是后序遍历的一种。 通常, “自底向上” 的递归函数 bottom_up(root) 为如下所示:

    1. return specific value for null node
    2. left_ans = bottom_up(root.left)          // call function recursively for left child
    3. right_ans = bottom_up(root.right)        // call function recursively for right child
    4. return answers                           // answer <-- left_ans, right_ans, root.val
    

    让我们继续讨论前面关于树的最大深度的问题,但是使用不同的思维方式:对于树的单个节点,以节点自身为根的子树的最大深度x是多少?

    如果我们知道一个根节点,以其子节点为根的最大深度为l和以其子节点为根的最大深度为r,我们是否可以回答前面的问题? 当然可以,我们可以选择它们之间的最大值,再加上1来获得根节点所在的子树的最大深度。 那就是 x = max(l,r)+ 1。

    这意味着对于每一个节点来说,我们都可以在解决它子节点的问题之后得到答案。 因此,我们可以使用“自底向上“的方法。下面是递归函数 maximum_depth(root) 的伪代码:

    1. return 0 if root is null                 // return 0 for null node
    2. left_depth = maximum_depth(root.left)
    3. right_depth = maximum_depth(root.right)
    4. return max(left_depth, right_depth) + 1  // return depth of the subtree rooted at root
    
    

    以下是java代码的参考:

    public int maximum_depth(TreeNode root) {
    	if (root == null) {
    		return 0;                                   // return 0 for null node
    	}
    	int left_depth = maximum_depth(root.left);
    	int right_depth = maximum_depth(root.right);
    	return Math.max(left_depth, right_depth) + 1;	// return depth of the subtree rooted at root
    }
    

    总结:

    了解递归并利用递归解决问题并不容易。
    当遇到树问题时,请先思考一下两个问题:

    1. 你能确定一些参数,从该节点自身解决出发寻找答案吗? 你可以使用这些参数和节点本身的值来决定什么应该是传递给它子节点的参数吗?
    2. 如果答案都是肯定的,那么请尝试使用 “自顶向下” 的递归来解决此问题。

    或者你可以这样思考:对于树中的任意一个节点,如果你知道它子节点的答案,你能计算出该节点的答案吗? 如果答案是肯定的,那么 “自底向上” 的递归可能是一个不错的解决方法。

  • 相关阅读:
    1030 完美数列 (25 分)
    1029 旧键盘 (20 分)
    数据库命令失败原因汇总
    代码有中文括号,导致错误
    win10笔记本触控板使用指南
    (已解决)vsC#控制台应用添加System.Windows.Forms引用失败(精通C#)
    ildasm中Ctrl+M闪退的问题(已解决, 精通C# 15.1)
    C#控制台应用(.NET Core)添加System.Windows.Forms失败(已解决)
    知识点_指针_增加对指针的理解
    自己写出的Bug_应是%f却写成%d
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13308083.html
Copyright © 2020-2023  润新知