当前位置: 首页 > wzjs >正文

山河集团建设有限公司网站拼多多关键词排名查询

山河集团建设有限公司网站,拼多多关键词排名查询,室内设计师资格证书,mvc做的网站如何发布访问首先总结一下二叉树中非常常见的递归方法 二叉树常见递归方式总结 1. 前序遍历(Preorder Traversal) 访问顺序:根 -> 左 -> 右 def preorder(root):if not root:returnprint(root.val) # 访问根节点preorder(root.left) # 递归左…

首先总结一下二叉树中非常常见的递归方法

二叉树常见递归方式总结

1. 前序遍历(Preorder Traversal)

访问顺序:根 -> 左 -> 右

def preorder(root):if not root:returnprint(root.val)  # 访问根节点preorder(root.left)  # 递归左子树preorder(root.right)  # 递归右子树

2. 中序遍历(Inorder Traversal)

访问顺序:左 -> 根 -> 右

def inorder(root):if not root:returninorder(root.left)  # 递归左子树print(root.val)  # 访问根节点inorder(root.right)  # 递归右子树

后序遍历(Postorder Traversal)

访问顺序:左 -> 右 -> 根

def postorder(root):if not root:returnpostorder(root.left)  # 递归左子树postorder(root.right)  # 递归右子树print(root.val)  # 访问根节点

4. 层序遍历(Level Order Traversal)

使用队列(BFS 方式)

from collections import dequedef level_order(root):if not root:return []queue = deque([root])result = []while queue:node = queue.popleft()result.append(node.val)if node.left:queue.append(node.left)if node.right:queue.append(node.right)return result

为什么书写二叉树递归时容易无从下手?

我们可以发现,二叉树的递归方式其实非常简单易懂,但在真正书写时,往往会陷入迷茫。这里总结出几个常见的原因:

1. 递归边界不清晰

递归的本质是拆分问题,最终必须有一个清晰的终止条件。

  • 许多时候,我们在书写递归时,并没有考虑清楚递归的最小子问题是什么,导致递归终止条件模糊。
  • 例如,在遍历二叉树时,通常需要设定递归的边界条件,以防止访问空节点时报错。

2. 过分纠结于递归细节

递归的核心思想是"假设子问题已经解决",然后只关注当前层的计算。

  • 递归是自顶向下拆解问题,但很多时候,我们在编写代码时,容易去关注每一步的具体执行,而不是从整体思考。
  • 解决方法是站在更高的层次思考,假设递归函数已经能正确处理子树,然后只关心当前层需要做什么。

3. 递归三部曲不熟练

解决二叉树问题,通常可以按照以下三步进行思考:

  • 确定递归函数的作用:明确这个函数的输入和输出,思考它的返回值如何帮助解决问题。
  • 确定递归终止条件:考虑最小规模的情况,比如空节点、叶子节点等。
  • 确定单层递归的逻辑:关注当前层要执行的操作,并递归调用左右子树。

4. 递归方式选择不清晰

二叉树的常见递归方式包括:

  • 先序遍历(Preorder):先访问根节点,再访问左子树,最后访问右子树。
  • 中序遍历(Inorder):先访问左子树,再访问根节点,最后访问右子树。
  • 后序遍历(Postorder):先访问左子树,再访问右子树,最后访问根节点。
  • 层序遍历(Level Order):按层次从上到下、从左到右遍历树中的每个节点。
  • 分治法(Divide & Conquer):将问题拆分成子问题,递归求解后合并结果。

5. 递归与回溯的结合不熟练

某些二叉树问题需要在递归过程中进行回溯,例如路径搜索问题。

  • 递归过程中,可能需要在回溯时撤销当前操作,以确保不影响其他递归路径。
  • 这类问题通常涉及路径存储、状态恢复等操作。

如何克服这些问题?

  1. 明确递归边界:思考最小子问题,明确递归终止条件。
  2. 假设递归已经解决子问题:避免过分关注细节,关注当前层逻辑。
  3. 牢记递归三部曲:思考递归的作用、终止条件和单层逻辑。
  4. 熟练掌握不同的递归方式:明确何时使用先序、中序、后序、层序遍历。
  5. 学会结合回溯:当递归涉及路径或状态恢复时,记得回溯以维护正确性。

牢记:递归的本质是分解问题 -> 解决子问题 -> 合并答案,只需关注当前层,剩下的交给递归即可!

结合例题深入理解递归

在掌握了二叉树递归的基本思想后,我们通过几道经典例题来深入理解递归的应用方式。

例题 1:二叉树的最大深度–简单

题目描述
给定一个二叉树,找出其最大深度。
二叉树的最大深度是指从根节点到最远叶子节点的最长路径上的节点数。

递归边界

  • 如果当前节点为空,直接返回 0,表示空节点的深度为 0

当前层(节点)需要做的操作

  • 递归求解左子树的最大深度 left_depth
  • 递归求解右子树的最大深度 right_depth
  • max(left_depth, right_depth) + 1 作为当前节点的最大深度。
class Solution:def maxDepth(self, root: TreeNode) -> int:if not root:return 0return max(self.maxDepth(root.left), self.maxDepth(root.right)) + 1

例题 2:对称二叉树–简单

题目描述
给定一个二叉树,找出其最大深度。
二叉树的最大深度是指从根节点到最远叶子节点的最长路径上的节点数。

递归边界

  • 如果两个子树 root1root2 都为空,说明对称,返回 True
  • 如果只有一个子树为空或者它们的值不同,则不对称,返回 False

当前层(节点)需要做的操作

  • 递归检查 root1 的左子树和 root2 的右子树是否对称。
  • 递归检查 root1 的右子树和 root2 的左子树是否对称。
  • 只有在这两个条件都满足的情况下,整棵树才是对称的。
class Solution:def isSymmetric(self, root: Optional[TreeNode]) -> bool:def dfs(root1, root2):if not root1 and not root2:return Trueif not root1 or not root2 or root1.val != root2.val:return Falsereturn dfs(root1.left, root2.right) and dfs(root1.right, root2.left)return dfs(root, root)

例题 3:二叉树的直径–简单

题目描述

给定一棵二叉树,找到它的直径。二叉树的直径指的是任意两个节点之间最长路径的长度,这个路径可能经过根节点,也可能不经过根节点。


递归边界

  • root == None 时,说明到达了空节点,此时返回 0,表示该子树的深度为 0

当前层(节点)需要做的操作

  1. 递归计算左子树的深度 left_depth右子树的深度 right_depth
  2. 更新二叉树的直径:二叉树的直径等于某个节点的左子树深度 + 右子树深度,因此 diameter = max(diameter, left_depth + right_depth)
  3. 返回当前节点的深度,即 max(left_depth, right_depth) + 1

代码实现

class Solution:def diameterOfBinaryTree(self, root: Optional[TreeNode]) -> int:diameter = 0  # 用于记录直径def tree_depth(root):nonlocal diameterif not root:return 0left_depth = tree_depth(root.left)right_depth = tree_depth(root.right)# 更新直径diameter = max(diameter, left_depth + right_depth)return max(left_depth, right_depth) + 1tree_depth(root)return diameter

例题 4:验证二叉搜索树(BST)

题目描述

给定一个二叉树,判断其是否为二叉搜索树(Binary Search Tree,BST)。
BST 的定义:

  1. 对于任意一个节点,其左子树所有节点的值必须小于当前节点的值。
  2. 对于任意一个节点,其右子树所有节点的值必须大于当前节点的值。
  3. 左右子树也必须分别是二叉搜索树

递归边界

  • root is None 时,说明已经遍历到空节点,返回 True,表示此分支没有违反 BST 规则。

当前层(节点)需要做的操作

  1. 取出当前节点值 x = root.val
  2. 检查 BST 规则
    • x 必须严格大于左边界 left,小于右边界 right(即 left < x < right)。
  3. 递归检查左子树
    • 左子树的所有节点必须在范围 (left, x) 内。
  4. 递归检查右子树
    • 右子树的所有节点必须在范围 (x, right) 内。
  5. 只有当前节点满足 BST 规则,并且左右子树都是 BST 时,返回 True

代码实现

class Solution:def isValidBST(self, root: Optional[TreeNode], left=float('-inf'), right=float('inf')) -> bool:if root is None:return Truex = root.valreturn left < x < right and \self.isValidBST(root.left, left, x) and \self.isValidBST(root.right, x, right)

例题 5:二叉搜索树中的第 K 小元素

题目描述

给定一棵二叉搜索树(BST),找到其中第 k 小的元素。
BST 性质:

  • 左子树所有节点的值小于根节点值。
  • 右子树所有节点的值大于根节点值。
  • 中序遍历二叉搜索树可得到递增序列

递归边界

  • node is None 时,直接返回,表示当前路径已无可访问节点。

当前层(节点)需要做的操作

  1. 递归访问左子树(优先访问左子树,因为中序遍历先访问左子树)。
  2. 访问当前节点:
    • count += 1 记录访问的节点数量。
    • count == k 时,找到第 k 小元素,存入 result 并返回。
  3. 递归访问右子树。

代码实现

class Solution:def kthSmallest(self, root: Optional[TreeNode], k: int) -> int:def dfs(node):nonlocal count, resultif not node:returndfs(node.left)  # 递归左子树count += 1  # 访问当前节点if count == k:result = node.valreturndfs(node.right)  # 递归右子树count = 0  # 计数器result = None  # 结果变量dfs(root)  # 开始中序遍历return result

例题 6:二叉树展开为单链表

题目描述

给定一个二叉树,原地将其展开为单链表。
要求:

  • 展开后的单链表按照前序遍历顺序排列
  • 左子树为空,右子树指向下一个节点。

递归边界

  • root is None,返回,不进行任何操作。

当前层(节点)需要做的操作

  1. 递归展开右子树 flatten(root.right)(保证后处理的节点按前序遍历顺序)。
  2. 递归展开左子树 flatten(root.left)(确保左子树的展开完成)。
  3. 修改指针
    • root.right = self.head(将当前节点的右指针指向已展开部分)。
    • root.left = None(清空左指针,确保符合单链表要求)。
    • self.head = root(更新 head,使其指向当前节点)。

代码实现

class Solution:head = None  # 记录单链表的头节点def flatten(self, root):if root is None:returnself.flatten(root.right)  # 先递归右子树self.flatten(root.left)   # 再递归左子树root.left = None  # 清空左子树root.right = self.head  # 右子树指向已展开部分self.head = root  # 更新 head,使当前节点成为链表头

例题 7:路径总和 III

题目描述

给定一个二叉树的 root 和一个整数 targetSum,计算二叉树中和等于 targetSum路径总数

要求

  • 路径不一定从根节点开始,也不一定到叶子节点
  • 路径方向必须是向下的(从父节点到子节点)。

递归边界

  • node is None 时,直接返回,不做任何计算。

当前层(节点)需要做的操作

  1. 计算当前前缀和
    cur_sum += node.val
  2. 查找符合条件的路径
    统计 pre_sum_count[cur_sum - targetSum] 作为当前符合要求的路径条数,并累加到 self.ans
  3. 更新前缀和计数
    pre_sum_count[cur_sum] += 1
  4. 递归遍历左右子树
    • dfs(node.left, cur_sum)
    • dfs(node.right, cur_sum)
  5. 回溯,恢复状态
    • pre_sum_count[cur_sum] -= 1
      这一操作确保回溯时不影响其他路径的计算。

代码实现

class Solution:def pathSum(self, root: Optional[TreeNode], targetSum: int) -> int:from collections import defaultdictpre_sum_count = defaultdict(int)pre_sum_count[0] = 1  # 处理从根节点开始的路径情况self.ans = 0def dfs(node, cur_sum):if not node:returncur_sum += node.val  # 计算当前前缀和# 查找当前前缀和是否存在匹配的路径self.ans += pre_sum_count[cur_sum - targetSum]# 更新前缀和计数pre_sum_count[cur_sum] += 1# 递归遍历左右子树dfs(node.left, cur_sum)dfs(node.right, cur_sum)# 回溯,恢复状态(去掉当前节点贡献的前缀和)pre_sum_count[cur_sum] -= 1dfs(root, 0)return self.ans

例题 8:二叉树的最近公共祖先

题目描述

给定一个二叉树的根节点 root 和两个节点 pq,返回这两个节点的最近公共祖先

最近公共祖先的定义是:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”


递归边界

  • rootNone 时,返回 None,因为没有节点可以是祖先。
  • rootpq 时,返回 root,表示找到了其中一个节点。

当前层(节点)需要做的操作

  1. 递归查找左右子树

    • left = self.lowestCommonAncestor(root.left, p, q)
    • right = self.lowestCommonAncestor(root.right, p, q)
  2. 判断左右子树是否都找到了

    • 如果左右子树都找到了节点(即 leftright 都非 None),那么当前节点 root 就是最近公共祖先。
  3. 返回找到的节点

    • 如果只找到了左子树的节点,返回左子树的节点;如果只找到了右子树的节点,返回右子树的节点。

代码实现

class Solution:def lowestCommonAncestor(self, root: TreeNode, p: TreeNode, q: TreeNode) -> TreeNode:if root in (None, p, q):return rootleft = self.lowestCommonAncestor(root.left, p, q)right = self.lowestCommonAncestor(root.right, p, q)if left and right:  # 左右都找到return root  # 当前节点是最近公共祖先return left or right
http://www.dtcms.com/wzjs/277889.html

相关文章:

  • 渭南市住房和城乡建设局网站怎么在百度上推广自己
  • 建设网站免费模板合肥网站优化技术
  • 商城网站怎么做推广方案seo服务顾问
  • 吉林省吉林市国内搜索引擎优化的公司
  • 中国移动app免费下载seo1短视频网页入口营销
  • 设计一个网页具体步骤站长工具seo下载
  • 广州哪家公司做网站合肥网站排名
  • 花乡做网站公司nba季后赛最新排名
  • 可靠的网站建设流程网络广告名词解释
  • 石嘴山网站seo百度关键词屏蔽
  • 怎么自己做视频网站seo的优点和缺点
  • 网站右下角视频代码发稿吧
  • 河池做网站培训机构
  • 做网站要学一些什么泉州百度推广咨询
  • 深圳市宝安网站建设小红书怎么推广
  • 朝阳网站制作公司友情链接网站大全
  • 网站制作合作协议本溪seo优化
  • 微网站开发需要几个人外包客服平台
  • 最好科技广州网站建设网站关键词推广
  • 微网站怎么做的好名字如何提高网站seo排名
  • web浏览器在哪里打开seo黑帽技术有哪些
  • 成都正规集团网站制作维护推广联系方式
  • 白云做网站SEO宁波谷歌seo推广公司
  • 深圳建设网站公司微信广告朋友圈投放
  • 小程序开发公司小程序开发公司网站seo站群软件
  • 网站备案网址百度指数分是什么
  • 聊城集团网站建设报价商丘seo博客
  • 可以做水果的团购网站手机网页设计制作网站
  • 微网站可以做商城吗互联网全网推广
  • wordpress 文章 附件网站推广与优化平台