LeetCode94:二叉树的中序遍历

题目介绍

题目:94. 二叉树的中序遍历
描述:给定一个二叉树,返回它的中序遍历。
输入:

 [1,null,2,3]
   1
    \
     2
    /
   3

输出:[1,3,2]

进阶: 递归算法很简单,你可以通过迭代算法完成吗?

题目理解 & 解题思路

题目理解:最基本的遍历之一。

中序遍历:先中序遍历左子树,再访问根节点,再中序遍历右子树

解题思路:可以使用递归和迭代算法来完成

注意点

  • 注意:先序遍历是从上往下看,中序遍历和后序遍历是从下往上看
  • 以根访问顺序决定是什么遍历
  • 左子树都是优先右子树

自己的解法实现

#!/usr/bin/env python
# Definition for a binary tree node.
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

class Solution:
    def inorderTraversal(self, root: TreeNode) -> List[int]:
        if not root: return []
        stack = []
        res = []
        node = root

        while node or stack:
            while node:
                stack.append(node)
                node = node.left
            node = stack.pop()
            res.append(node.val)
            node = node.right
        return res

    def inorderTraversal2(self, root: TreeNode) -> List[int]:
        def inorder(node, res):
            if node is None: return
            inorder(node.left, res)
            res.append(node.val)
            inorder(node.right, res)
        res = []
        inorder(root, res)
        return res

网上比较优秀的解法

解法一

定义 inorder(root) 表示当前遍历到 root 节点的答案,那么按照定义,我们只要递归调用 inorder(root.left) 来遍历 root 节点的左子树,然后将 root 节点的值加入答案,再递归调用inorder(root.right) 来遍历 root 节点的右子树即可,递归终止的条件为碰到空节点。

时间复杂度:O(n),其中 n 为二叉树节点的个数。二叉树的遍历中每个节点会被访问一次且只会被访问一次。

空间复杂度:O(n),空间复杂度取决于递归的栈深度,而栈深度在二叉树为一条链的情况下会达到 O(n) 的级别。

 def inorderTraversal2(self, root: TreeNode) -> List[int]:
        def inorder(node, res):
            if node is None: return
            inorder(node.left, res)
            res.append(node.val)
            inorder(node.right, res)
        res = []
        inorder(root, res)
        return res

解法二

颜色标记法:

  • 使用颜色标记节点的状态,新节点为白色,已访问的节点为灰色。
  • 如果遇到的节点为白色,则将其标记为灰色,然后将其右子节点、自身、左子节点依次入栈。
  • 如果遇到的节点为灰色,则将节点的值输出。
  • 如要实现前序、后序遍历,只需要调整左右子节点的入栈顺序即可。
def inorderTraversal5(self, root: TreeNode) -> List[int]:
        WHITE, GREY = 0, 1
        res = []
        stack = [(WHITE, root)]
        while stack:
            color, node = stack.pop()
            if node is None: continue
            if color == WHITE:
                stack.append((WHITE, node.right))
                stack.append((GREY, node))
                stack.append((WHITE, node.left))
            else:
                res.append(node.val)

        return res

解法三

二叉树的中序遍历,在遍历时会先访问根节点,然后是左子树,再是右子树,只不过处理节点值是放在访问完左子树之后(这就是区别于先序、后序遍历的地方)。

最重点的内容就是:不管是先序中序还是后序,查找流程都是从上到下,先左后右。只是输出的时机不同。

先序就是发现了先输出,再先左后右。
中序就是发现了先存着,当左边遍历完了,再把存着的输出出来。
后序就是发现了先存着,当左边和右边都遍历完了,再把存着的输出出来。

def inorderTraversal8(self, root: TreeNode) -> List[int]:
        # 递归1:二叉树遍历最易理解和实现版本
        if not root: return []
        # 前序递归
        # return [root.val] + self.preorderTraversal(root.left) + self.preorderTraversal(root.right)
        # 中序递归
        return self.inorderTraversal8(root.left) + [root.val] + self.inorderTraversal8(root.left)
        # 后序递归
        # return self.postorderTraversal(root.left) + self.postorderTraversal(root.right) + [root.val]

    def inorderTraversal9(self, root: TreeNode) -> List[int]:
        res = []
        # 通用模板,可以适应不同的题目,添加参数、增加返回条件、修改进入递归条件、自定义返回值
        def dfs(node):
            if not node: return
            # 前序递归
            # res.append(node.val)
            # dfs(node.left)
            # dfs(node.right)

            # 中序递归
            dfs(node.left)
            res.append(node.val)
            dfs(node.right)

            # 后序递归
            # dfs(node.left)
            # dfs(node.right)
            # res.append(node.val)
        dfs(root)

        return res

    def inorderTraversal10(self, root: TreeNode) -> List[int]:
        # 迭代2:前、中、后序遍历通用模板(只需一个栈的空间)
        if not root: return []
        res = []
        stack = []
        node = root
        # 中序,模板:先用指针找到每颗子树的最左下角,然后进行进出栈操作
        while stack or node:
            while node:
                stack.append(node)
                node = node.left

            node = stack.pop()
            res.append(node.val)
            node = node.right

        return res
        # # 前序,相同模板
        # while stack or cur:
        #     while cur:
        #         res.append(cur.val)
        #         stack.append(cur)
        #         cur = cur.left
        #     cur = stack.pop()
        #     cur = cur.right
        # return res

        # # 后序,相同模板
        # while stack or cur:
        #     while cur:
        #         res.append(cur.val)
        #         stack.append(cur)
        #         cur = cur.right
        #     cur = stack.pop()
        #     cur = cur.left
        # return res[::-1]

    # 迭代3:标记法迭代(需要双倍的空间来存储访问状态):
    # 前、中、后、层序通用模板,只需改变进栈顺序或即可实现前后中序遍历,
    # 而层序遍历则使用队列先进先出。0表示当前未访问,1表示已访问。

    def inorderTraversal11(self, root: TreeNode) -> List[int]:
        if not root: return []
        res = []
        stack = [(0, root)]
        while stack:
            flag, node = stack.pop()
            if not node: continue
            if flag == 0:
                # 前序,标记法
                # stack.append((0, node.right))
                # stack.append((0, node.left))
                # stack.append((1, node))

                # # 后序,标记法
                # stack.append((1, cur))
                # stack.append((0, cur.right))
                # stack.append((0, cur.left))

                # # 中序,标记法
                stack.append((0, node.right))
                stack.append((1, node))
                stack.append((0, node.left))
            else:
                res.append(node.val)
        return res

    def inorderTraversal12(self, root: TreeNode) -> List[int]:
        if not root: return []
        res = []
        queue = [(0, root)]
        while queue:
            flag, node = queue.pop(0)
            if not node: continue
            if flag == 0:
                # 层序遍历这三个的顺序无所谓,因为是队列,只弹出队首元素
                queue.append((1, node.left))
                queue.append((0, node))
                queue.append((0, node.right))
            else:
                res.append(node.val)
        return res

对自己解法的改进

颜色标记法和通用模板要好好学习

相关知识总结和思考

深入思考:对于这些题目,还是会处于一看就懂,写了会忘的阶段,还是要多多练习

你可能感兴趣的:(LeetCode94:二叉树的中序遍历)