Beispiel #1
0
    def test_equality(self):
        """ Examples of valid equality tests for NamedTuples """
        p1 = Path.home()
        p2 = Path.cwd()
        n1a = TreeNode.new(p1)
        n1b = TreeNode.new(p1)
        n2a = TreeNode.new(p2)
        n2b = TreeNode.new(p2)
        for tn in (n1a, n1b, n2a, n2b):
            tn.add(Path("./data"))
            tn.add(Path("requirements.txt"))

        # NamedTuples implement compare
        assert n1a == n1b
        assert n1a != n1b._replace(files=[])

        # Deep compare works
        case = "case_100"
        tn1 = Customs(case, FileType.PICKLE).read()
        tn2 = copy.deepcopy(tn1)

        assert tn1 == tn2
        # Fragile - this is tied to case_100 dir list order
        tn2.dirs[16].dirs[0].files.append('foo')
        assert tn1 != tn2
    def test_normalRamify_WithKeys(self):
        treeNode = TreeNode(1)
        treeNode.ramify(range(3), ['kid' + str(x) for x in range(3)])

        self.assertEqual(treeNode.children,
                         {'kid' + str(x): x
                          for x in range(3)})
    def next(self):
        self.head_node = self.head_q.get()
        str_world_state = str(self.head_node.world_state)
        if str_world_state not in self.explored_by_head:
            self.explored_by_head[str_world_state] = self.head_node
        self.expansion_count += 1
        if str_world_state in self.explored_by_tail:
            self.tail_node = self.explored_by_tail[str_world_state]
            return False

        self.tail_node = self.tail_q.get()
        str_world_state = str(self.tail_node.world_state)
        if str_world_state not in self.explored_by_tail:
            self.explored_by_tail[str_world_state] = self.tail_node
        self.expansion_count += 1
        if str_world_state in self.explored_by_head:
            self.head_node = self.explored_by_head[str_world_state]
            return False

        new_world_states = self.world.get_moves(self.head_node.world_state)
        for state in new_world_states:
            node = TreeNode(self.head_node, state)
            self.head_q.put(node)

        new_world_states = self.world.get_moves(self.tail_node.world_state)
        for state in new_world_states:
            node = TreeNode(self.tail_node, state)
            self.tail_q.put(node)

        return True
def main():
    solver = Solution()
    for test in [[1, None, 2, None, None, 3]]:
        root = TreeNode()
        root.build_from_list(test)
        print(solver.preorderTraversal(root))
    pass
Beispiel #5
0
 def splitTree(self, node):
     """
     according to best split feature, split datasets into multiple parts
     :@ param node: input Tree Node
     :@ rparam children of input node
     """
     children = []
     bestFeature = self.chooseSplitFeature(node)
     if bestFeature < 0:
         return children
     for key in node.uniformAttribute[bestFeature][1]:
         newDataSet = []
         if key.startswith('<='):
             newDataSet = [
                 instance for instance in node.dataSet
                 if instance[bestFeature] <= float(key.split('<= ')[1])
             ]
         elif key.startswith('>'):
             newDataSet = [
                 instance for instance in node.dataSet
                 if instance[bestFeature] > float(key.split('> ')[1])
             ]
         else:
             newDataSet = [
                 instance for instance in node.dataSet
                 if instance[bestFeature] == key
             ]
         newNode = TreeNode(newDataSet, copy.deepcopy(node.attribute),
                            copy.deepcopy(node.classOutput))
         newNode.splitFeatureName = node.attribute[bestFeature][0]
         newNode.splitFeatureValue = key
         children.append(newNode)
     return children
    def test_errorRamify_childrenPresent(self):
        with self.assertRaises(Exception) as cm:
            treeNode = TreeNode(1)
            treeNode['child0'] = TreeNode(2)
            treeNode.ramify([1, 1])

        self.assertEqual('Node already has 1 children', str(cm.exception))
Beispiel #7
0
 def pruneTree(self, root: TreeNode) -> TreeNode:
     if not root:
         return None
     root.left = self.pruneTree(root.left)
     root.right = self.pruneTree(root.right)
     if root.val == 0 and not root.left and not root.right:
         return None
     return root
Beispiel #8
0
 def __init__(self,
              centerPt=Point(0, 0, 'center'),
              dimension=1,
              max_points=1,
              max_depth=4):
     self.max_points = max_points
     self.max_depth = max_depth
     self.root = TreeNode(centerPt, dimension, max_points, max_depth, 0)
    def test_errorSetItem_DifferentValueTypes(self):
        with self.assertRaises(Exception) as cm:
            treeNode = TreeNode(1)
            treeNode['child0'] = TreeNode(2.0)

        self.assertEqual(
            'Parent and child nodes\' values must share the same type',
            str(cm.exception))
def build_from_traversals(preorder, inorder):
    if not preorder or not inorder:
        return None
    root_val = preorder[0]
    i = inorder.find(root_val)
    root = TreeNode(root_val)
    root.left = build_from_traversals(preorder[1:i+1], inorder[0:i])
    root.right = build_from_traversals(preorder[i+1:], inorder[i+1:])
def build_from_traversals(preorder, inorder):
    if not preorder or not inorder:
        return None
    root_val = preorder[0]
    i = inorder.find(root_val)
    root = TreeNode(root_val)
    root.left = build_from_traversals(preorder[1:i + 1], inorder[0:i])
    root.right = build_from_traversals(preorder[i + 1:], inorder[i + 1:])
def makeBalancedTree(nums):
  if not nums:
    return None

  midpoint = len(nums) / 2

  node = TreeNode(nums[midpoint])
  node.left = solution(nums[:midpoint])
  node.right = solution(nums[(midpoint + 1):])
  return node
Beispiel #13
0
def create_by_pre_order(values):
    value = values.pop(0)

    if value == 0:
        return None

    node = TreeNode(value=value)
    node.left = create_by_pre_order(values)
    node.right = create_by_pre_order(values)
    return node
Beispiel #14
0
def searchingByBFS():
    #Pointing to the global variables
    global initialConfiguration
    global goalState
    global visitedNodes
    global nodesToExpand
    global success
    global stacksDoesntMatter
    #At the begin our current state is null
    actualNode = TreeNode(None, None, None, 0)

    #Creating the node for the initial configuration
    initialConfiguration = TreeNode(None, initialConfiguration, None, 0)

    #Initial state will be the first node to expand
    nodesToExpand.append(initialConfiguration)

    #Adding the first node to expand to the visited list
    visitedNodes.append(initialConfiguration.state)

    #Iterate while there are nodes to expand and the goal state has been not reached
    while (nodesToExpand and not (success)):
        actualNode = nodesToExpand.pop(0)
        visitedNodes.append(actualNode.state)
        if (isFinalState(actualNode.state)):
            success = actualNode
            return True
        #For the actual node, we need to expande it and check all the possible combinations
        for originStack in range(len(actualNode.state)):
            for destinationStack in range(len(actualNode.state)):
                expandedActualNode = copy.deepcopy(actualNode.state)
                #If origin is not empty, the origin and destination are different and the height in the destination is the correct
                #We can make a movement
                if (expandedActualNode[originStack]
                        and originStack != destinationStack and
                        len(expandedActualNode[destinationStack]) < maxHeight):
                    #Remove from origin stack
                    expandedActualNode[originStack].pop(0)
                    #Add to destination stack
                    expandedActualNode[destinationStack].append(
                        actualNode.state[originStack][0])
                    #If the new state has not been visited
                    if (not (visitedNodes.count(expandedActualNode))):
                        #Calculate cost
                        newCost = 1 + abs(originStack -
                                          destinationStack) + actualNode.cost
                        #Create the new node
                        newNode = TreeNode(actualNode, expandedActualNode,
                                           [originStack, destinationStack],
                                           newCost)
                        #Add it as the list for expansion
                        nodesToExpand.append(newNode)
                        #Add it to the visited list
                        #visitedNodes.append(newNode.state)
    return False
Beispiel #15
0
    def deleteNode(self, root: TreeNode, key: int) -> TreeNode:
        """"""
        v_root = TreeNode(-1)
        v_root.right = root
        parent = v_root
        node = root
        while node:
            if node.val == key:
                break
            elif node.val > key:
                node = node.left
            else:
                node = node.right
            parent = node
        if not node:
            return root

        def find_max_from_left(node: TreeNode) -> TreeNode:
            """从BST树节点的左子树中找到值最大的节点"""
            if not node:
                return
            p = node
            node = node.left
            while node and node.right:
                p = node
                node = node.right
            p.right = None
            return node

        def find_min_from_right(node: TreeNode) -> TreeNode:
            """从BST树节点的右子树中找到值最小的节点"""
            if not node:
                return
            p = node
            node = node.right
            while node and node.left:
                p = node
                node = node.left
            p.left = None
            return node

        if node.left:
            max_sub_node = find_max_from_left(node)
            node.val = max_sub_node.val
        elif node.right:
            min_sub_node = find_min_from_right(node)
            node.val = min_sub_node.val
        else:
            if node.val < parent.val:
                parent.left = None
            else:
                parent.right = None
        return v_root.right
def build_coinflip_tree(k, value=""):
    '''
    INPUT: int
    OUTPUT: TreeNode

    Return the root of a binary tree representing all the possible outcomes
    form flipping a coin k times.
    '''
    node = TreeNode(value)
    if k != 0:
        node.left = build_coinflip_tree(k - 1, value + "H")
        node.right = build_coinflip_tree(k - 1, value + "T")
    return node
def build_coinflip_tree(k, value=""):
    '''
    INPUT: int
    OUTPUT: TreeNode

    Return the root of a binary tree representing all the possible outcomes
    form flipping a coin k times.
    '''
    node = TreeNode(value)
    if k != 0:
        node.left = build_coinflip_tree(k - 1, value + "H")
        node.right = build_coinflip_tree(k - 1, value + "T")
    return node
Beispiel #18
0
def build_coinflip_tree(k, value=""):
    """Return the root of a binary tree for flipping coin k times.
    Root represents all the possible outcomes from flipping a coin k times.
    Parameters
    ----------
    int
    Returns
    -------
    TreeNode
    """
    node = TreeNode(value)
    if k != 0:
        node.left = build_coinflip_tree(k - 1, value + "H")
        node.right = build_coinflip_tree(k - 1, value + "T")
    return node
Beispiel #19
0
def searchingRecursive(initialState, visitedNodes):
    node = initialState
    nodeInitialState = node.state
    stateLength = len(nodeInitialState)
    cost = node.cost
    if(nodeInitialState == goalState):
        return node
    else:
        for i in range(0, stateLength):
            for j in range(0, stateLength):
                if ((len(nodeInitialState[j])) > 0 and i != j and (len(nodeInitialState[i])) < maxHeight):
                    newState = copy.deepcopy(nodeInitialState)
                   
                    #Put the last container j -> i 
                    newState[i].append(newState[j].pop())
                    if (not(visitedNodes.count(newState))):
                        movements = [i, j]
                        
                        #New cost
                        #1 Picking up the container and Putting the container down + 1 for Moving the container one stack to the left or right + the accumulated cost of the path
                        newCost = 1 + abs(i - j) + cost
                        
                        #New node
                        newNode = TreeNode(node, newState, movements, newCost)
                        
                        #Visited list
                        visitedNodes.append(newState)

                        #Recursive call
                        auxDFS = searchingRecursive(newNode, visitedNodes)
                        if(auxDFS != None):
                            return auxDFS
    return None
Beispiel #20
0
def aStar():
    path = []
    finalCost = 0
    while nodesToExpand:
        node = nodesToExpand.pop()
        #Result found
        if isFinalState(node.state):
            finalCost, path = adaptSolution(node)
            return finalCost, path
        visitedNodes.append(node.state)
        for i, stack in enumerate(node.state):
            for j, new_stack in enumerate(node.state):
                auxState = copy.deepcopy(node.state)
                if i != j and len(stack) > 0 and len(new_stack) < maxHeight:
                    newState, newStateCost = moveBlock(auxState, i, j)
                    newNode = TreeNode(node, newState, [i, j],
                                       newStateCost + node.cost)

                    #if the new node has not been visited, it is added to the visited list
                    if newNode.state not in visitedNodes and not any(
                            n.state == newNode.state for n in nodesToExpand):
                        nodesToExpand.append(newNode)
                        nodesToExpand.sort(key=operator.attrgetter('cost'),
                                           reverse=True)
                    #if the node was visited before, we verify if the node's cost is higher than the new one
                    else:
                        for n in nodesToExpand:
                            if n.state == newNode.state and n.cost > newNode.cost:
                                nodesToExpand.remove(n)
                                nodesToExpand.append(newNode)
                                nodesToExpand.sort(
                                    key=operator.attrgetter('cost'),
                                    reverse=True)
    return finalCost, path
Beispiel #21
0
 def translate(self):
     """
     We serialize either a TreeNode or an id_dict. After reading, call
     this method to ensure all source formats are available.
     Assumes we have
     """
     if self.treenode:
         # Create id_dict from TreeNode - only pickle
         self.id_dict = self.treenode.to_id_dict()
         self.tn_dict = self.treenode.to_tn_dict()
     elif self.id_dict:
         # Create TreeNode from id_dict - all other serializations
         # If serialization produces an id_dict, we must create the tn_dict
         self.tn_dict = {}
         for id, node in self.id_dict.items():
             if node.is_dir():
                 self.tn_dict[id] = TreeNode(me=node, files=[], dirs=[])
                 
         # Define dir hierarchy
         # Also identify root node to remove one tn_dict traversal
         for tn in self.tn_dict.values():
             if not tn.me.parent_id:
                 self.treenode = tn
             else:
                 self.tn_dict[tn.me.parent_id].dirs.append(tn)
             
         # Merge files into dir hierarchy
         for node in self.id_dict.values():
             if not node.is_dir():
                 self.tn_dict[node.parent_id].files.append(node)
     else:
         raise ValueError("No internal format to translate.")
Beispiel #22
0
 def test_basic_relation(self):
   parent = TreeNode(9)
   node = TreeNode(8)
   left = TreeNode(6)
   right = TreeNode(7)
   node.parent = parent
   node.left = left
   node.right = right
   self.assertEqual(id(node.parent), id(parent))
   self.assertEqual(id(node.left), id(left))
   self.assertEqual(id(node.right), id(right))
   self.assertEqual(id(left.parent), id(node))
   self.assertEqual(id(right.parent), id(node))
   self.assertEqual(id(node.parent), id(parent))
   self.assertEqual(id(parent.left), id(node))
   self.assertTrue(parent.key > left.key)
   self.assertTrue(parent > left)
def collect_data_recurse(p: Path, tree_node: TreeNode,
                         exclusions: Set[str]) -> None:
    """ Recurse dirs starting at tree_node, collecting information """
    for item in p.iterdir():
        # NOTE: If we cannot create the node, it will not be added and we will not recurse
        child = tree_node.add(item)
        if item.is_dir() and item.name not in exclusions and child:
            collect_data_recurse(item, child, exclusions)
Beispiel #24
0
def decision_tree(examples, attributes, bin_targets):
    all_same = check_all_same(bin_targets)

    if all_same:
        return TreeNode(None, True, bin_targets.iloc[0].iloc[0])
    elif not attributes:
        # Majority Value
        return TreeNode(None, True, majority_value(bin_targets))
    else:
        best_attribute = choose_best_decision_attr(examples, attributes,
                                                   bin_targets)
        tree = TreeNode(best_attribute)
        for vi in range(0, 2):
            examples_i = examples.loc[examples[best_attribute] == vi]
            indices = examples_i.index.values
            bin_targets_i = bin_targets.ix[indices]

            if examples_i.empty:
                # Majority Value
                return TreeNode(None, True, majority_value(bin_targets))
            else:
                attr = set(attributes)
                attr.remove(best_attribute)
                tree.set_child(vi,
                               decision_tree(examples_i, attr, bin_targets_i))

        return tree
Beispiel #25
0
    def from_pre_post(pre: List[int], post: List[int]) -> TreeNode:
        if not pre:
            return None

        root = TreeNode(pre[0])

        # 左右边界判定
        if len(pre) == 1:
            return root

        left_val = pre[1]
        left_count = post.index(left_val) + 1

        root.left = Construct.from_pre_post(pre[1:left_count + 1],
                                            post[0:left_count])
        root.right = Construct.from_pre_post(pre[left_count + 1:],
                                             post[left_count:-1])

        return root
 def next(self):
     self.current = self.q.get()
     # self.print_status()
     if self.world.is_solved(self.current.world_state):
         return False
     new_world_states = self.world.get_moves(self.current.world_state)
     for state in new_world_states:
         node = TreeNode(self.current, state)
         self.q.put(node)
     return True
Beispiel #27
0
 def insert(self, data, root=None):
     if self.root is None:
         if root is None:
             self.root = TreeNode(data)
             return
         else:
             self.root = root
     if root.data > data:
         if root.left is None:
             root.left = TreeNode(data)
         else:
             self.insert(data, root.left)
     elif root.data < data:
         if root.next is None:
             root.next = TreeNode(data)
         else:
             self.insert(data, root.next)
     else:
         print("value already exists")
Beispiel #28
0
def create_by_pre_in_order(values1, values2):
    if not values1 or not values2:
        return None

    root_value = values1[0]
    i = 0
    while values2[i] != root_value:
        i += 1

    left_values1 = values1[1:i + 1]
    left_values2 = values2[:i]
    right_values1 = values1[i + 1:]
    right_values2 = values2[i + 1:]
    node = TreeNode(value=root_value)

    node.left = create_by_pre_in_order(left_values1, left_values2)
    node.right = create_by_pre_in_order(right_values1, right_values2)

    return node
Beispiel #29
0
def dir_counts_recurse(node: TreeNode, indent: int = 0) -> None:
    """ Print all directories and node counts """
    fc = len(node.files)
    dc = len(node.dirs)
    descendants = 0
    for item in node.iter():
        descendants += 1
    print(
        f"{dc: >4}  {fc: >4}  {descendants: >4}  {' ' * indent}/{node.me.name}"
    )
    for d in node.dirs:
        dir_counts_recurse(d, indent + 2)
Beispiel #30
0
class DynamicQuadTree:
    def __init__(self,
                 centerPt=Point(0, 0, 'center'),
                 dimension=1,
                 max_points=1,
                 max_depth=4):
        self.max_points = max_points
        self.max_depth = max_depth
        self.root = TreeNode(centerPt, dimension, max_points, max_depth, 0)

    def __len__(self):
        return len(self.root)

    def __iter__(self):
        return iter(self.root)

    def __contains__(self, point):
        return self.root.exist(point)

    def insert(self, point):
        return self.root.insert(point)

    def remove(self, point):
        return self.root.remove(point)

    def update(self, new_point, old_point):
        return self.root.update(new_point, old_point)

    def query_range(self, boundary):
        return self.root.query_range(boundary)

    def knn(self, point, k):
        return self.root.knn(point, k)
Beispiel #31
0
    def add_node(self, node, data, index):
        if data == -1:
            return node

        if node is None:
            return TreeNode(data)

        if index % 2 == 1:
            node.set_left(self.add_node(node.get_left(), data, index))
        else:
            node.set_right(self.add_node(node.get_right(), data, index))

        return node
def cross_validation_error(df_labels, N, df_data, segments):

    error_list = {
        'anger': 1,
        'disgust': 2,
        'fear': 3,
        'happiness': 4,
        'sadness': 5,
        'surprise': 6
    }
    for e in cnst.EMOTIONS_LIST:
        total_error_for_emotion = 0
        error_list[1] = 2
        print("/\ Decision tree building for emotion:", e)
        binary_targets = util.filter_for_emotion(df_labels,
                                                 cnst.EMOTIONS_DICT[e])
        for test_seg in segments:
            test_df_data, test_df_targets, train_df_data, train_df_targets = util.divide_data(
                test_seg, N, df_data, df_labels)
            root = dtree.decision_tree(train_df_data, set(cnst.AU_INDICES),
                                       train_df_targets)
            TreeNode.plot_tree(root, e)
            # root = decision_tree(df_data, set(cnst.AU_INDICES), binary_targets)
            print("/\ Decision tree built.\n")
            count = 0
            # Counts number of incorrectly predicted tests
            for i in test_df_data.index.values:
                count += 1 - TreeNode.dfs2(root, test_df_data.loc[i],
                                           test_df_targets.loc[i].at[0])

            error = count / len(test_df_targets)
            total_error_for_emotion += error
            print()

        total_error_for_emotion /= 10
        error_list[e] = total_error_for_emotion
        print()
        print("Total error:", total_error_for_emotion)
        print()
Beispiel #33
0
 def buildSubTree(self, trainingExamples, currNode):
     """
     method to build our tree - this build method uses OO concepts which we use during our prediction later on
     """
     if self.attributesAndValues == []:
         return currNode
     divisionAttribute = self.getDivisionAttribute(trainingExamples)
     if currNode == None: # rootptr
         currNode = TreeNode(divisionAttribute.attrName)
     else:
         currNode.name = divisionAttribute.attrName
     # divide up our data based on the attribute we got back
     subLists = {}
     for attrValue in divisionAttribute.attrValues:
         subLists[attrValue] = []
     for example in trainingExamples:
         # if the example attribute matches our division attributes, add training example to correct sublist
         for attribute in example.attributes:
             if attribute.attrName == divisionAttribute.attrName:
                 subLists[attribute.attrValues[0]].append(example)
     # check if any of the sublists would require us to return a leaf node
     for subListKey in subLists:
         childNode = TreeNode()
         subList = subLists[subListKey]
         if subList == []: # no training examples, default to most common target value
             childNode.isLeaf = True
             childNode.targetValue = "p"
             currNode.childrenNodes[subListKey] = childNode
         elif self.isLeafNode(subList):
             childNode.isLeaf = True
             childNode.targetValue = subList[0].targetValue
             currNode.childrenNodes[subListKey] = childNode
         else:
             currNode.childrenNodes[subListKey] = childNode
             # recursively build using each sublist
             self.buildSubTree(subList, childNode)
     #return the root node with everything built on
     return currNode
Beispiel #34
0
def utSplitFeature():
    """
    unit test for function [chooseSplitFeature]
    """
    from data_provider import data_provider
    attribute, dataset = data_provider('../test.arff')
    root = TreeNode(dataset, attribute)
    curTree = DecisionTree(root)
    bestFeature = curTree.chooseSplitFeature(root)
    try:
        assert (bestFeature == 0)
        print '[chooseSplitFeature] TEST PASS'
    except AssertionError:
        print '[chooseSplitFeature] TEST FAILED'
Beispiel #35
0
def utCreateTree():
    """
    unit test for function [createTree]
    examine the tree structure
    compared graph with:
        http://pages.cs.wisc.edu/~yliang/cs760_fall18/homework/hw2/diabetes/m=4.txt
    """
    from data_provider import data_provider
    attribute, dataset = data_provider('../diabetes_train.arff')
    root = TreeNode(dataset, attribute)
    curTree = DecisionTree(root)
    curTree.createTree(root, 4)
    curTree.printTree(root, 0)
    print '---------------- please compare this graph with the url ------------------'
    print 'http://pages.cs.wisc.edu/~yliang/cs760_fall18/homework/hw2/diabetes/m=4.txt'
Beispiel #36
0
def build_coinflip_tree(k, flips=''):
    if k == 0:
        return None
    else:
        return TreeNode(flips, build_coinflip_tree(k - 1, flips + 'H'), build_coinflip_tree(k - 1, flips + 'T'))
        # node.left = build_coinflip_tree(node, k-1)
        # node.right = build_coinflip_tree(node, k-1)

if __name__ == '__main__':
    # build a tree
    #     1
    #    / \
    #   2   3
    #  /
    # 4
    t1 = TreeNode(1)
    t1.left = TreeNode(2)
    t1.right = TreeNode(3)
    t1.left.left = TreeNode(4)

    # build a tree
    #     1
    #    / \
    #   2   3
    #  /   /
    # 4   5
    t2 = TreeNode(1)
    t2.left = TreeNode(2)
    t2.right = TreeNode(3)
    t2.left.left = TreeNode(4)
    t2.right.left = TreeNode(5)
                ltail.left = None
                ltail.right = None
                return root, ltail
            elif root.left is not None and root.right is not None:
                lhead, ltail = gao(root.left)
                rhead, rtail = gao(root.right)
                root.left = None
                root.right = lhead
                lhead.left = None
                ltail.left = None
                ltail.right = rhead
                rhead.left = None
                rtail.left = None
                rtail.right = None
                return root, rtail

        gao(root)


solver = Solution()

root5 = TreeNode()
root5.build_from_list([1,2,3,4])
solver.flatten(root5)
print(root5.to_dict())

root4 = TreeNode()
root4.build_from_list([2,1,4,None,None,3,5])
solver.flatten(root4)
print(root4.to_dict())

class Solution:
    # @param root, a tree node
    # @return a list of lists of integers

    def levelOrderBottom(self, root):
        if root is None:
            return []
        result = []
        cur_level = [root]
        next_level = []
        while len(cur_level) > 0:
            values = []
            for node in cur_level:
                values.append(node.val)
                if node.left is not None:
                    next_level.append(node.left)
                if node.right is not None:
                    next_level.append(node.right)
            cur_level = next_level
            next_level = []
            result.append(values)
        return result[::-1]

if __name__ == '__main__':
    root = TreeNode()
    root.build_from_list([3, 9, 20, None, None, 15, 7])
    res = Solution().levelOrderBottom(root)
    print(res)
        # bfs
        depth = 1
        found_leaf = False
        cur_depth = [root]
        next_depth = []
        while True:
            next_depth = []
            for node in cur_depth:
                is_leaf = True
                if node.left is not None:
                    next_depth.append(node.left)
                    is_leaf = False
                if node.right is not None:
                    next_depth.append(node.right)
                    is_leaf = False
                if is_leaf is True:
                    found_leaf = True
                    break
            if found_leaf is True:
                break
            else:
                depth += 1
                cur_depth = next_depth
        return depth


if __name__ == '__main__':
    root = TreeNode()
    root.build_from_list(list(range(10)))
    print(Solution().minDepth(root))