From a36358e06868764fab05b2821497991aded21256 Mon Sep 17 00:00:00 2001 From: Lane Zhang Date: Wed, 23 Oct 2024 10:22:58 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E4=BA=8C=E5=8F=89=E6=A0=91=E7=9A=84?= =?UTF-8?q?=E8=BF=AD=E4=BB=A3=E9=81=8D=E5=8E=86.md=20=E5=8A=A0=E5=85=A5=20?= =?UTF-8?q?Python=20=E7=89=88=E6=9C=AC=E7=9A=84=E5=90=8E=E5=BA=8F=E9=81=8D?= =?UTF-8?q?=E5=8E=86=E6=96=B0=E8=A7=A3=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/二叉树的迭代遍历.md | 38 ++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/problems/二叉树的迭代遍历.md b/problems/二叉树的迭代遍历.md index 5f59c388..00d24692 100644 --- a/problems/二叉树的迭代遍历.md +++ b/problems/二叉树的迭代遍历.md @@ -303,6 +303,44 @@ class Solution: return result[::-1] ``` +#### Python 后序遍历的迭代新解法: +* 本解法不同于前文介绍的`逆转前序遍历调整后的结果`,而是采用了对每个结点直接处理。 + +```python +class Solution: + def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]: + values = [] + stack = [] + popped_nodes = set() # 记录值已经被收割了的 nodes + current = root + + while current or stack: + if current: # 一次处理完一个结点和他的左右儿子结点,不处理孙子结点,孙子结点由左右儿子等会分别处理。 + stack.append(current) # 入栈自己 + + if current.right: + stack.append(current.right) # 入栈右儿子 + + if current.left: # 因为栈是后进先出,后序是‘左右中’,所以后加左儿子 + stack.append(current.left) # 入栈左儿子 + + current = None # 会导致后面A处出栈 + continue + + node = stack.pop() # A处,出的是左儿子,如果无左儿子,出的就是右儿子,如果连右儿子也没有,出的就是自己了。 + + # 如果 node 是叶子结点,就可以收割了;如果左右儿子都已经被收割了,也可以收割 + if (node.left is None or node.left in popped_nodes) and \ + (node.right is None or node.right in popped_nodes): + popped_nodes.add(node) + values.append(node.val) + continue + + current = node # 不符合收割条件,说明 node 下还有未入栈的儿子,就去入栈 + + return values +``` + ### Go: > 迭代法前序遍历 From bf540436f290e509fa8ae5d77cb75f250c154866 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lane=20Zhang=20=28=E5=BC=A0=E5=81=A5=29?= Date: Wed, 23 Oct 2024 10:33:48 +0800 Subject: [PATCH 2/3] =?UTF-8?q?Update=20=E4=BA=8C=E5=8F=89=E6=A0=91?= =?UTF-8?q?=E7=9A=84=E8=BF=AD=E4=BB=A3=E9=81=8D=E5=8E=86.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/二叉树的迭代遍历.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/problems/二叉树的迭代遍历.md b/problems/二叉树的迭代遍历.md index 00d24692..3b4b30fb 100644 --- a/problems/二叉树的迭代遍历.md +++ b/problems/二叉树的迭代遍历.md @@ -240,14 +240,14 @@ class Solution { # 前序遍历-迭代-LC144_二叉树的前序遍历 class Solution: def preorderTraversal(self, root: TreeNode) -> List[int]: - # 根结点为空则返回空列表 + # 根节点为空则返回空列表 if not root: return [] stack = [root] result = [] while stack: node = stack.pop() - # 中结点先处理 + # 中节点先处理 result.append(node.val) # 右孩子先入栈 if node.right: @@ -264,19 +264,19 @@ class Solution: def inorderTraversal(self, root: TreeNode) -> List[int]: if not root: return [] - stack = [] # 不能提前将root结点加入stack中 + stack = [] # 不能提前将root节点加入stack中 result = [] cur = root while cur or stack: - # 先迭代访问最底层的左子树结点 + # 先迭代访问最底层的左子树节点 if cur: stack.append(cur) cur = cur.left - # 到达最左结点后处理栈顶结点 + # 到达最左节点后处理栈顶节点 else: cur = stack.pop() result.append(cur.val) - # 取栈顶元素右结点 + # 取栈顶元素右节点 cur = cur.right return result ``` @@ -291,7 +291,7 @@ class Solution: result = [] while stack: node = stack.pop() - # 中结点先处理 + # 中节点先处理 result.append(node.val) # 左孩子先入栈 if node.left: @@ -304,7 +304,7 @@ class Solution: ``` #### Python 后序遍历的迭代新解法: -* 本解法不同于前文介绍的`逆转前序遍历调整后的结果`,而是采用了对每个结点直接处理。 +* 本解法不同于前文介绍的`逆转前序遍历调整后的结果`,而是采用了对每个节点直接处理。 ```python class Solution: @@ -315,7 +315,7 @@ class Solution: current = root while current or stack: - if current: # 一次处理完一个结点和他的左右儿子结点,不处理孙子结点,孙子结点由左右儿子等会分别处理。 + if current: # 一次处理完一个节点和他的左右儿子节点,不处理孙子节点,孙子节点由左右儿子等会分别处理。 stack.append(current) # 入栈自己 if current.right: @@ -329,7 +329,7 @@ class Solution: node = stack.pop() # A处,出的是左儿子,如果无左儿子,出的就是右儿子,如果连右儿子也没有,出的就是自己了。 - # 如果 node 是叶子结点,就可以收割了;如果左右儿子都已经被收割了,也可以收割 + # 如果 node 是叶子节点,就可以收割了;如果左右儿子都已经被收割了,也可以收割 if (node.left is None or node.left in popped_nodes) and \ (node.right is None or node.right in popped_nodes): popped_nodes.add(node) From 8b7027f2b7e911f4474c9c4c545c3a031639e16f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lane=20Zhang=20=28=E5=BC=A0=E5=81=A5=29?= Date: Wed, 23 Oct 2024 12:30:11 +0800 Subject: [PATCH 3/3] =?UTF-8?q?Update=20=E4=BA=8C=E5=8F=89=E6=A0=91?= =?UTF-8?q?=E7=9A=84=E8=BF=AD=E4=BB=A3=E9=81=8D=E5=8E=86.md=20=E8=B0=83?= =?UTF-8?q?=E6=95=B4=E6=B3=A8=E9=87=8A=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/二叉树的迭代遍历.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/problems/二叉树的迭代遍历.md b/problems/二叉树的迭代遍历.md index 3b4b30fb..79b54929 100644 --- a/problems/二叉树的迭代遍历.md +++ b/problems/二叉树的迭代遍历.md @@ -304,14 +304,14 @@ class Solution: ``` #### Python 后序遍历的迭代新解法: -* 本解法不同于前文介绍的`逆转前序遍历调整后的结果`,而是采用了对每个节点直接处理。 +* 本解法不同于前文介绍的`逆转前序遍历调整后的结果`,而是采用了对每个节点直接处理。这个实现方法在面试中不容易写出来,在下一节,我将改造本代码,奉上代码更简洁、更套路化、更容易实现的统一方法。 ```python class Solution: def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]: values = [] stack = [] - popped_nodes = set() # 记录值已经被收割了的 nodes + popped_nodes = set() # 记录值已经被收割了的 nodes,这是关键,已经被收割的节点还在树中,还会被访问到,但逻辑上已经等同于 null 节点。 current = root while current or stack: