Leetcode36 [二叉树专题] 基本概念 & #144 #94 Binary Tree Preorder Traversal & Binary Tree Inorder Traversal

本文介绍了二叉树的基本概念,包括前序、中序和后序遍历。详细讲解了LeetCode上的#144二叉树前序遍历和#94二叉树中序遍历问题,提供了迭代和递归两种解题思路,并分析了两种方法的运行时间。在实现过程中,特别强调了迭代解法中栈的使用和处理特殊情况的技巧。

基本概念:

Pre-Order Traversal: Root -> Left -> Right

In-Order Traversal: Left -> Root -> Right (常用语二分查找)

这个F之后的顺序是literally的先左后中,就看pointer的方向。

Post-Order Traversal: Left -> Right -> Root (常用于删除节点,以及数学运算)

Recursive or Iterative:尝试每题都用两种思维解决

#144 Binary Tree Preorder Traversal

Given the root of a binary tree, return the preorder traversal of its nodes' values.

解题思路:

借用stack的特点,last in first out. 存完root节点的信息,往后跟着从stack里pop出来的left node,如果有的话,再是right node.

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        out = []
        stack = [root]
        while stack:
            node = stack.pop()
            if node:
                out.append(node.val)
                stack.append(node.right)
                stack.append(node.left)
        return out

runtime:

看了15,16ms的解法也是用的stack。So下一题:

#94 Binary Tree Inorder Traversal

Given the root of a binary tree, return the inorder traversal of its nodes' values.

Example 1:

 解题思路:

iterative思路

更符合思路直觉,虽然写起来很复杂。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        if not root:
            return root
        
        res = stack = []
        
        while True:
            while root.left:            # reach the deepest left node 
                stack.append(root)
                root = root.left
            
            res.append(root.val)             # output left node first
            root = stack.pop()               # move back to the parent node
            
            while root:
                res.append(root.val)         # output root node
                if root.right: 
                    root = root.right             # move to the right node if it has one
                    break                       # to see if it has left node
                else:
                    root = stack.pop()           # move back to the upper parent node
            
            return res

很奇怪的是,报错了。

说root是int object,没有attribute val。 

改了res, stack = [], []之后。报错才消失。所以是我没有搞明白res = stack = [] 和 res, stack = [], []的区别。研究了一下,前者是不同的变量指向同一个对象。任意一个变,另外一个也跟着变。后者指向不同的对象,所以不会影响。

但改了之后,我之前的方法还存在一个问题,就是当stack为空集的时候,无法.pop()。没有考虑stack没了之后的情况。所以必须把stack存在这个条件放进循环条件里。

 参考了Neetcode频道的解法,才发现stack那一步还是要先于判断左节点在不在,不在也要现存。看似短期多了一步先存再看左节点有没有,实则长期逻辑更为统一和简单,因为把左节点和母节点的stack.pop()和res.append()都合为一步处理了。

另外排除root是空集那一步也是多余。可以不用。root不存在,直接返回res空list。

最后离开循环的终止条件是无右节点也无母节点。

重新写了一遍。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        res, stack = [], []
        
        while root or stack:
            while root:            # reach the deepest left node 
                stack.append(root)
                root = root.left
                
            root = stack.pop()
            res.append(root.val)             # output left node first
            root = root.right             # move to the right node if it has one
                    
        return res

 runtime:

recursive思路

属于自己想不到系列……

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        res = []
        
        def inorder(root):
            
            if not root: return
            inorder(root.left)
            res.append(root.val)
            inorder(root.right)
            
            return res
        
        inorder(root)
        return res

 runtime:

应该是recursive这里还缺基本功,但暂时不知道要补什么方面的功课。先走着。

<think>我们正在讨论二叉树的相关知识点。用户之前已经询问了二叉树的核心概念和专业名词,现在用户提出了几个具体问题: 1. 满二叉树和完全二叉树的区别 2. BFS path的含义 3. Pre-order traversal和In-order traversal的定义 根据用户提供的引用,我们可以参考以下信息: 引用[1]提到了二叉树的遍历方式,包括前序、中序、后序和层序。 引用[2]进一步解释了前序遍历、中序遍历和后序遍历,以及广度优先搜索(BFS)。 引用[3]和[4]则提供了层序遍历的代码示例。 因此,我们将针对这三个问题逐一解答。 1. 满二叉树(Full Binary Tree)和完全二叉树(Complete Binary Tree)的区别: - 满二叉树:每个结点都有0个或2个子结点,也就是说,除了叶子结点外,每个结点都有两个子结点。而且,所有叶子结点都在同一层上。满二叉树的层数$h$与结点总数$n$的关系为:$n = 2^h - 1$。 - 完全二叉树:除了最后一层外,其他层的结点数都达到最大值,并且最后一层的结点都连续集中在最左边。也就是说,完全二叉树是满二叉树在最后一层从右向左连续缺失若干个结点而形成的。完全二叉树常用于数组存储(堆结构)。 2. BFS path的含义: - BFS(Breadth-First Search,广度优先搜索)是一种按层次遍历的方法,从根结点开始,一层一层地向下遍历。在二叉树中,BFS通常指层序遍历(Level Order Traversal)。 - BFS path通常指的是从根结点到目标结点所经过的结点序列,且这个序列是按照BFS遍历的顺序得到的。但更常见的,BFS用于寻找最短路径(在中,根到叶子的最短路径就是层数最小的路径)。例如,在无权图中,BFS可以找到两点之间的最短路径,而在二叉树中,BFS遍历的路径就是按层展开的结点序列。 3. Pre-order traversal(前序遍历)和In-order traversal(中序遍历)的定义: - 前序遍历(Pre-order traversal):按照“根结点-左子-右子”的顺序遍历二叉树。即先访问根结点,然后递归地前序遍历左子,最后递归地前序遍历右子[^1][^2]。 - 中序遍历(In-order traversal):按照“左子-根结点-右子”的顺序遍历二叉树。即先递归地中序遍历左子,然后访问根结点,最后递归地中序遍历右子[^1][^2]。 另外,我们可以通过一个例子来展示这两种遍历方式: 1 / \ 2 3 / \ 4 5 前序遍历:1 -> 2 -> 4 -> 5 -> 3 中序遍历:4 -> 2 -> 5 -> 1 -> 3 根据用户要求,我们将在回答中使用数学公式的LaTeX格式,并生成相关问题。 注意:用户提供的引用中并没有直接定义“BFS path”,所以我们根据图论中的常规用法进行解释。在中,BFS遍历得到的路径序列实际上是按层访问的序列,而最短路径指的是层数最少的路径(因为是无环的,所以从根到任意结点的路径是唯一的,但BFS可以保证我们按层数递增的顺序访问结点,因此最先访问到目标结点的路径就是最短路径)。 最后,按照要求生成相关问题。 </think>### 二叉树核心概念解析 #### 一、满二叉树 vs 完全二叉树 | **特性** | 满二叉树 (Full Binary Tree) | 完全二叉树 (Complete Binary Tree) | |----------------|------------------------------------------|-------------------------------------------| | **定义** | 所有非叶子结点都有两个子结点 | 除最后一层外完全填充,最后一层左对齐填充[^1] | | **数学关系** | 高度$h$的共有$2^h - 1$个结点 | 高度$h$的结点数$n$满足:$2^{h-1} \leq n < 2^h$ | | **结构示例** | ``` 1 → 所有非叶结点都有2个子结点 / \ 2 3 / \ / \ 4 5 6 7``` | ``` 1 → 最后一层左对齐 / \ 2 3 / \ / 4 5 6``` | | **应用场景** | 理论模型 | 堆结构实现、内存管理 | #### 二、BFS Path(广度优先路径) 1. **定义**: 在广度优先遍历(Breadth-First Search)中形成的路径,按层级顺序访问结点[^2][^3] 2. **核心特性**: - 访问顺序:从根节点开始,逐层从左到右访问 - 路径长度:记录从根节点到目标结点的边数(即深度) - 数学表示:的高度$h$时,第$k$层最多有$2^k$个结点 3. **算法实现**(队列结构): ```python def bfs(root): queue = collections.deque([root]) while queue: node = queue.popleft() process(node) # 处理当前结点 if node.left: queue.append(node.left) # 左子结点入队 if node.right: queue.append(node.right) # 右子结点入队 ``` 4. **应用场景**: - 最短路径搜索(中任意两节点间唯一路径)[^4] - 层次遍历(如LeetCode 102题) - 二叉树序列化 #### 三、遍历方式对比 | **遍历方式** | 访问顺序 | 伪代码 | 应用场景 | |-------------|----------------------|-------------------------------|--------------------------| | **前序遍历**<br>(Pre-order) | 根结点 → 左子 → 右子 | ```visit(root)```<br>```preorder(root.left)```<br>```preorder(root.right)``` | 复制结构<br>前缀表达式生成 | | **中序遍历**<br>(In-order) | 左子 → 根结点 → 右子 | ```inorder(root.left)```<br>```visit(root)```<br>```inorder(root.right)``` | 二叉搜索排序输出<br>表达式解析 | **遍历示例**(同一棵): ``` A / \ B C / \ D E ``` - **前序遍历**:A → B → D → E → C (根结点优先) - **中序遍历**:D → B → E → A → C (根结点在中间) ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值