【Leetcode】二叉树问题整理笔记 之 普通遍历取值



遍历二叉树

257. Binary Tree Paths - 输出二叉树所有根到叶的路径

n/a

Solution:

class Solution:
    def get_bt_paths(self, root):
        if root.left is None and root.right is None:
            return [[root.val]]
        me = root

        ret = []
        if root.left:
            for path in self.get_bt_paths(root.left):
                path.append(me.val)
                ret.append(path)
        if root.right:
            for path in self.get_bt_paths(root.right):
                path.append(me.val)
                ret.append(path)                

        return ret
        
    def binaryTreePaths(self, root: TreeNode) -> List[str]:
        if root is None:
            return []
        all_paths = self.get_bt_paths(root)
        ret = []
        for path in all_paths:
            ret.append("->".join([str(_) for _ in reversed(path)]))
        return ret

n/a


94. Binary Tree Inorder Traversal – 中序遍历

n/a

Solution:

class Solution:
    def recursive_inorder_traversal(self, root):
        if root is None:
            return []
        left = self.recursive_inorder_traversal(root.left)
        middle = root.val
        right = self.recursive_inorder_traversal(root.right)
        
        ret = left
        ret.append(middle)
        ret.extend(right)
        return ret

    def iterative_inorder_traversal(self, root):
        if root is None:
            return []

        ret = []
        stack = []
        dummy_root = TreeNode(None)
        dummy_root.right = root
        DO = True
        curr = dummy_root
        while DO or curr.right or stack:
            if DO:  # for "do{...}while();"
                DO = False
            if curr.right:
                curr = curr.right
                while curr.left:
                    stack.append(curr)
                    curr = curr.left

            elif stack:
                curr = stack.pop()
            
            ret.append(curr.val)

        return ret

    def inorderTraversal(self, root: TreeNode) -> List[int]:
        # return self.recursive_inorder_traversal(root)
        return self.iterative_inorder_traversal(root)

n/a
第一次是递归的方式,速度比较常规。
第二次提交使用迭代的方式,发现运行速度比较快 - faster than 99%+ submissions


144. Binary Tree Preorder Traversal – 前序遍历

前序遍历:先取节点值,再分别取左右子树的值。

class Solution:
    def recursive_preorder_traversal(self, root):
        if root is None:
            return []
        
        ret = [root.val]
        ret.extend(self.recursive_preorder_traversal(root.left))
        ret.extend(self.recursive_preorder_traversal(root.right))
        return ret

    def iterative_preorder_traversal(self, root):
        if root is None:
            return []
        ret = []
        stack = []
        DO = True
        curr = root
        while DO or curr or stack:
            if DO:  # for "do{...}while();"
                DO = False
            if curr:
                while curr:
                    ret.append(curr.val)
                    stack.append(curr.right)
                    curr = curr.left
            elif stack:
                curr = stack.pop()

        return ret

    def preorderTraversal(self, root: TreeNode) -> List[int]:
        # return self.recursive_preorder_traversal(root)
        return self.iterative_preorder_traversal(root)

n/a

先做递归的 solution submit,后一个是迭代的 solution submit。


145. Binary Tree Postorder Traversal - 后序遍历

后序遍历:先分别取左右子节点值,最后取当前节点值

2020/07/10

这一题不知道为什么被算为 hard

Solution:

  1. 递归解法(十分简单):
    class Solution:
        def postorderTraversal(self, root: TreeNode) -> List[int]:
            def recursive(anode):
                if anode is None:
                    return []
                ans = (recursive(anode.left))
                ans.extend(recursive(anode.right))
                ans.append(anode.val)
                return ans
    
            return recursive(root)
    
    只要将“当前”节点的 value 在最后放入 answer 列表之中就可以了。
  2. 迭代解法:
    class Solution:
        def postorderTraversal(self, root: TreeNode) -> List[int]:
            if root is None:
                return []
    
            stack = []
            ans = []
    
            def do_expand(anode):
                if isinstance(anode, TreeNode):
                    stack.append(anode.val)
                    stack.append(anode.right)
                    stack.append(anode.left)
    
            do_expand(root)
            while stack:
                last = stack.pop()
                if isinstance(last, int):
                    ans.append(last)
                elif last is None:
                    continue
                elif isinstance(last, TreeNode):
                    do_expand(last)
    
            return ans
    

迭代遍历取值的写法比我上面 144. 的前序遍历和 94. 的中序遍历的迭代取值的方案要简洁地多,而且也比较好理解。我想可能是因为多做一些题,解决这类问题更熟练了。

迭代的思路是,不断地 .pop “缓存”队列的最后一个值,如果这个值是“子节点”,就对它以“前序遍历”或“中序遍历”或“后序遍历”的定义进行“拓展

不断地拓展、.pop、再拓展、再 .pop 最终就能遍历完。
[1,null,2,3] 为例(这个输入到 leetcode 中去可视化,就不截图了);
算法运行过程 stack 地变化如下:

[(1: TreeNode), ]                                      # expand
[(1: int), (2: TreeNode), (NULL), ]                    # continue
[(1: int), (2: TreeNode), ]                            # expand
[(1: int), (2: int), (NULL), (3: TreeNode)]            # expand
[(1: int), (2: int), (NULL), (3: int) (NULL) (NULL)]   # continue
[(1: int), (2: int), (NULL), (3: int) (NULL),]         # continue
[(1: int), (2: int), (NULL), (3: int), ]  # ans.append(last) ans: [3]
[(1: int), (2: int), (NULL), ]            # continue
[(1: int), (2: int), ]                    # ans.append(last) ans: [3, 2]
[(1: int), ]                              # ans: [3, 2, 1]

这个算法从我个人角度应该算是迭代解法地终极形式了,因为非常好理解,然后三种遍历方式都可以用,调整 expand 函数内部的顺序就是三种遍历方式的实现了。


538. Convert BST to Greater Tree - 中序遍历变体问题

n/a

Solution:

在解决方案上,这其实是一个中序遍历的变体。
先遍历到当前 root 节点的最右节点,然后一步一步往小于它的值增加。返回值是当前 root 节点的最左节点的最终值。

class Solution:
    def recursive(self, root: TreeNode, greater_sum: int) -> int:
        if root is None:
            return greater_sum

        sum_of_right = self.recursive(root.right, greater_sum)

        val = root.val + sum_of_right
        root.val = val
        
        sum_of_left = self.recursive(root.left, val)
        return sum_of_left

        
    def convertBST(self, root: TreeNode) -> TreeNode:
        if root is None:
            return None
        self.recursive(root, 0)
        return root

n/a


965. Univalued Binary Tree - 判断一棵二叉树是否只含有一个值

n/a
n/a
n/a

Solution:

class Solution:
    def is_all_the_same_val(self, root, key):
        if root is None:
            return True

        if root.val == key:
            return self.is_all_the_same_val(root.left, key) and self.is_all_the_same_val(root.right, key)

        return False

    def isUnivalTree(self, root: TreeNode) -> bool:
        if root is None:
            return True
        
        key = root.val
        return self.is_all_the_same_val(root, key)


993. Cousins in Binary Tree - 判断深度与父节点

n/a
n/a
n/a
n/a

Solution:

class Solution:
    def recursive(self, root, depth, key):
        if root is None or root.val == key:
            raise RuntimeError("shouldn't run here")

        depth += 1
        ret = False
        if root.left:
            if root.left.val == key:
                ret = (root, depth + 1)
            else:
                ret = self.recursive(root.left, depth, key)
        
        if ret is False:
            if root.right:
                if root.right.val == key:
                    ret = (root, depth + 1)
                else:
                    ret = self.recursive(root.right, depth, key)
        return ret

    def isCousins(self, root: TreeNode, x: int, y: int) -> bool:
        if root is None or root.val in (x, y):
            return False
        try:
            x_parent, x_depth = self.recursive(root, 0, x)
            y_parent, y_depth = self.recursive(root, 0, y)
            if x_depth == y_depth and x_parent is not y_parent:
                return True
        except Exception:
            return False

        return False

n/a

在提交之后,看到这个对比速度,我又考虑了一下有没有更快的办法。
然后想起来,如果按层遍历的化,应该速度会快很多。不过这题不难,就不改了。



遍历叶子节点

872. Leaf-Similar Trees

n/a
Consider all the leaves of a binary tree. From left to right order, the values of those leaves form a leaf value sequence.

n/a

For example, in the given tree above, the leaf value sequence is (6, 7, 4, 9, 8).

Two binary trees are considered leaf-similar if their leaf value sequence is the same.

Return true if and only if the two given trees with head nodes root1 and root2 are leaf-similar.

n/a

Solution:

class Solution:
    def recursive_traversal(self, root):
        ret = []
        if root.left:
            ret.extend(self.recursive_traversal(root.left))
        if root.right:
            ret.extend(self.recursive_traversal(root.right))
        
        if root.left is None and root.right is None:
            return [root.val]

        return ret

    def leafSimilar(self, root1: TreeNode, root2: TreeNode) -> bool:
        if root1 and root2:
            root1_vals = self.recursive_traversal(root1)
            root2_vals = self.recursive_traversal(root2)
            
            return root1_vals == root2_vals

        if root1 is None and root2 is None:
            return True

        return False

n/a



Reference



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值