带你清晰理解二叉树的递归与解题思路(框架思维!)

前言:

本篇博客会带你理解面对二叉树题型时的两种解题思维模式:(我先总结出来,不理解往下看)
1、是否可以通过遍历一遍二叉树得到答案?
如果可以,用一个 traverse 函数配合外部变量来实现,这叫「遍历」的思维模式。(就是根据当前节点的值来进行处理操作,可以得出答案)

2、是否可以定义一个递归函数,通过子问题(子树)的答案推导出原问题的答案?
如果可以,写出这个递归函数的定义,并充分利用这个函数的返回值,这叫「分解问题」的思维模式。(就是将问题分解为左右子树的问题,看看是否通过对左右子树进行处理可以得出答案)

但是无论使用哪种思维模式,你都需要思考
如果单独抽出一个二叉树节点,它需要做什么事情?需要在什么时候(前/中/后序位置)做? 其他的节点不用你操心,递归函数会帮你在所有节点上执行相同的操作。

🐕啥叫“框架思维”

先解释一下啥叫“框架思维”,就是看到一道算法题,你下意识的就想到用什么方法,甚至还没有仔细看题目限制条件,就可以基本将70%的代码写出来,剩下没写的就是限制条件。
(举个例子:就是英语考试的作文题,如果你有一套写作框架/模板(就是你背的英语作文模板),就能很快的完成一篇英语作文)

🏨深入理解前中后序

我们学习二叉树时,都学过前序遍历、中序遍历、后序遍历,先来回顾一下,找一下区别吧

在这里插入图片描述在这里插入图片描述在这里插入图片描述

是不是分别在前序位置、中序位置、后序位置上呢?那么它们的位置不同,产生的作用也不同
如果你意识到了这一点,证明你已经理解了它们作用不一样。

🪀前序位置与后序位置区别

你也注意到了,只要是递归形式的遍历(数组也能递归),都可以有前序位置和后序位置,分别在递归之前和递归之后.
所谓前序位置,就是刚进入一个节点(元素)的时候,后序位置就是即将离开一个节点(元素)的时候,那么进一步,你把代码写在不同位置,代码执行的时机也不同:
在这里插入图片描述

🎀下面以一个链表入手,让你理解前序位置与后序位置的区别,而二叉树无非是多了一个中序位置而已。

思考:如何倒序打印链表呢?如何正序打印链表呢

在这里插入图片描述
在这里插入图片描述

看到这里,你是否对这张图中内容理解了呢在这里插入图片描述
那么说回二叉树也是一样的,只不过多了一个中序位置罢了。
教科书里只会问你前中后序遍历结果分别是什么,所以对于一个只上过大学数据结构课程的人来说,他大概以为二叉树的前中后序只不过对应三种顺序不同的 List<Integer> 列表。
但是我想说,前中后序是遍历二叉树过程中处理每一个节点的三个特殊时间点,绝不仅仅是三个顺序不同的 List:

前序位置的代码在刚刚进入一个二叉树节点的时候执行;

后序位置的代码在将要离开一个二叉树节点的时候执行;

中序位置的代码在一个二叉树节点左子树都遍历完,即将开始遍历右子树的时候执行。

你注意本文的用词,我一直说前中后序「位置」,就是要和大家常说的前中后序「遍历」有所区别
你可以在前序位置写代码往一个 List 里面塞元素,那最后得到的就是前序遍历结果;但并不是说你就不可以写更复杂的代码做更复杂的事。
画成图,前中后序三个位置在二叉树上是这样:

在这里插入图片描述
你可以发现每个节点都有「唯一」属于自己的前中后序位置,所以其他的节点不用你操心,递归函数会帮你在所有节点上执行相同的操作。

两种解题思路:

二叉树题目的递归解法可以分两类思路,(无论题目是简单困难)

  • 第一类是遍历一遍二叉树得出答案,
  • 第二类是通过分解成左右子树问题计算出答案

下面用几道简单题来练习一下:

力扣 104.二叉树的最大深度

🎀力扣 104.二叉树的最大深度

给定一个二叉树 root ,返回其最大深度。
二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。在这里插入图片描述
提示:

  • 树中节点的数量在 [0, 104] 区间内
    -100 <= Node.val <= 100

🏅解法一能否利用分解为左右子树来推出结果

  public int maxDepth(TreeNode root) {
  //思路:能否利用遍历一次二叉树解决问题?可以,【前序位置,当前进入时++,后序位置,回溯退出时--】
        //思路:能否利用分解为左右子树来推出结果?可以,【后序位置】
        //思路2:
        if(root==null){
            return 0;
        }
        int leftDepth = maxDepth(root.left);//获取左子树的最大深度
        int rightDepth = maxDepth(root.right);//获取右子树的最大深度
        return Math.max(leftDepth,rightDepth)+1;
    }

🏅解法二能否利用遍历一次二叉树解决问题

 public int maxDepth(TreeNode root) {
        //思路:能否利用遍历一次二叉树解决问题?可以,【前序位置,当前进入时++,后序位置,回溯退出时--】
        //思路:能否利用分解为左右子树来推出结果?可以,【后序位置】
        //思路1:
        if(root==null){
            return 0;
        }
        maxDepth++;//进入当前节点
        maxDepth(root.left);//进入左子树
        res=Math.max(res,maxDepth);
        maxDepth(root.right);//进入右子树
        maxDepth--;//从右子树回溯到当前节点,深度-1
        return res;
    }

力扣 144.翻转二叉树

🎀力扣 144.翻转二叉树

给定一棵二叉树的根节点 root,请左右翻转这棵二叉树,并返回其根节点。
在这里插入图片描述

提示:

  • 树中节点的数量在 [0, 100] 区间内
    -100 <= Node.val <= 100

🏅解法一能否利用分解为左右子树来推出结果

 public TreeNode mirrorTree(TreeNode root) {
        //思路:是否能通过分解左右子树来解决问题
        
        if(root==null){
            return root;
        }
        TreeNode left= mirrorTree(root.left);
        TreeNode right= mirrorTree(root.right);
        //后序位置
        root.left=right;
        root.right=left;
        return root;
    }

🏅解法二能否利用遍历一次二叉树解决问题

public TreeNode mirrorTree(TreeNode root) {
        //思路:是否能通过一次二叉树遍历推出结果呢?可以
        if(root==null){
            return root;
        }
        //前序位置
        TreeNode temp=root.left;//先寄存当前节点的左子树
        root.left=root.right;
        root.right=temp;
        mirrorTree(root.left);
        mirrorTree(root.right);
        return root;
    }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
重建二叉树是一道经典的二叉树问题,其解题思路如下: 1. 首先,我们需要根据前序遍历序列和中序遍历序列来重建二叉树。前序遍历序列的第一个节点一定是二叉树的根节点,中序遍历序列中根节点左边的所有节点都属于二叉树的左子树,右边的所有节点都属于二叉树的右子树。 2. 我们可以通过前序遍历序列找到二叉树的根节点,然后在中序遍历序列中找到根节点的位置。根节点左边的所有节点都属于左子树,右边的所有节点都属于右子树。 3. 接下来,我们递归构建左子树和右子树。我们可以根据前序遍历序列和中序遍历序列中左右子树的节点数量确定左右子树的范围。 4. 重复以上步骤,直到遍历完整个序列,最终得到重建的二叉树。 下面是重建二叉树的代码实现,代码注释中有详细的解释。 ```python class TreeNode: def __init__(self, val=0, left=None, right=None): self.val = val self.left = left self.right = right def buildTree(preorder, inorder): """ :type preorder: List[int] :type inorder: List[int] :rtype: TreeNode """ # 如果前序遍历序列和中序遍历序列为空,返回None if not preorder or not inorder: return None # 前序遍历序列的第一个节点一定是二叉树的根节点 root_val = preorder[0] root = TreeNode(root_val) # 在中序遍历序列中找到根节点的位置 root_index = inorder.index(root_val) # 递归构建左子树和右子树 left_preorder = preorder[1:root_index+1] left_inorder = inorder[:root_index] left = buildTree(left_preorder, left_inorder) right_preorder = preorder[root_index+1:] right_inorder = inorder[root_index+1:] right = buildTree(right_preorder, right_inorder) # 将左右子树连接到根节点上 root.left = left root.right = right return root ``` 以上就是重建二叉树的详细解题思路和代码实现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

信计2102罗铠威

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值