Search code examples
pythondata-structuresbinary-searchinorder

Binary Tree Inorder Traversal - query


I am looking at LeetCode problem 94. Binary Tree Inorder Traversal:

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

For the above problem I tried the following code:

class Solution:
    def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        list1=[]
        if root==None:
            return None
            inorderTraversal(root.left)
            list1.append(root.val)
            inorderTraversal(root.right)
        print(list1)
        return list1

But it fails the most simple test cases, and gives errors.

I found a working solution:

class Solution:
    def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        list1=[]
        if root==None:
            return None
        def create_list(root,list1):
            if root==None:
                return
            create_list(root.left,list1)
            list1.append(root.val)
            create_list(root.right,list1)
        create_list(root,list1)
        print(list1)
        return list1

What is wrong with my code?

I would like to better understand how recursion works for Binary Trees. I can solve basic problems, but as the problem statement gets tougher, it gets hard to imagine/dry run what recursion would return.


Solution

  • These are the issues with the non-working code:

    • inorderTraversal is not a known function. It should be self.inorderTraversal so you access the method.

    • You have some dead code, as the statements after return None will never execute. The concerned statements should not be part of the if block and have less indentation

    • self.inorderTraversal should not return None. If the tree is empty, you should return an empty list, not None.

    • self.inorderTraversal returns a list, but you ignore the lists that are returned from the recursive calls. That means you lose information and those recursive calls do all their work for nothing. Instead, build the current list from those lists coming back from recursion.

    Here is what the code would look like if those issues are corrected:

    class Solution:
        def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
            list1 = []
            if root is None:
                return []
            list1 = self.inorderTraversal(root.left)
            list1.append(root.val)
            list1.extend(self.inorderTraversal(root.right))
            return list1
    

    This solution is however not memory efficient, as it keeps creating new lists from existing lists. A more pythonic way would be to create a generator function and collect the yielded values into one list:

    class Solution:
        def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
            def iterate(node):
                if node:
                    yield from iterate(node.left)
                    yield node.val
                    yield from iterate(node.right)
            
            return list(iterate(root))