Сгенерировать все допустимые деревья двоичного поиска по заданному списку значений

#python-3.x #recursion #binary-search-tree

#python-3.x #рекурсия #binary-search-tree

Вопрос:

Здравствуйте, я пытаюсь решить следующий вопрос по leetcode, [https://leetcode.com/problems/unique-binary-search-trees-ii /].

Я знаю, что у меня есть доступ к решению, но я попытался решить проблему по-своему, и я застрял, и я хотел бы знать, разрешима ли она так, как я это делаю. Вот код:

 class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

def generateTrees(myrange, n, res = None):
    if res == None:
        res = []
    if myrange == []:
        res.append(None)
        return
    for root in myrange:
        res.append(root)
        generateTrees([i for i in range(root) if i in set(myrange)], n, res) #leftchild
        generateTrees([i for i in range(root 1, n) if i in set(myrange)], n, res) #rightchild
    return res
  

Изначально myrange это просто список, содержащий значения узлов, и n это длина myrange .

То, как я это делаю, — это своего рода DFS, где я перебираю узлы, делая каждый из них корневым один раз, а затем я делаю то же самое для левого и правого поддеревьев, чтобы получить все комбинации. Но проблема, с которой я сталкиваюсь, заключается в том, что я не могу понять, как управлять res удалением элементов из него по мере возврата к моей рекурсии (и сделать так, чтобы он res содержал только допустимые bst, а затем помещал их в какой-то другой список, который будет моим фактическим результатом).

Я хотел бы получить некоторые указания или даже просто комментарии, если вы считаете, что мой подход верен или плох .. и т.д.

Комментарии:

1. Не уверен, какой порядок в формате вывода дерева. Вопрос на самом деле не объясняет этот формат. Или цель заключается в выводе экземпляров TreeNode ? Ваш код никогда не создает экземпляр этого класса?

2. Вы правы, это не так, я пытался решить это, создав список списков в том же формате, что и в примере с leetcode, когда я мог бы вывести список корневых узлов…

Ответ №1:

Проблемы:

  • Как вы упомянули, ваш код создает только один список, к которому он продолжает добавляться.
  • Даже если вы это исправите, списки никогда не будут отображаться в порядке, подобном BFS, что, по-видимому, предполагает пример вопроса.
  • Для выбранного корня вам нужно перечислить все комбинации его возможных левых поддеревьев с его возможными правыми поддеревьями — декартово произведение, если хотите. Эта логика отсутствует в вашем коде.

Я бы:

  • не передавать res в качестве аргумента рекурсивной функции. Просто верните его, и пусть вызывающий объект разбирается с ним.
  • не используйте диапазоны, поскольку это только усложняет ситуацию. if i in set(myrange) Кажется неэффективным способом получить перекрытие между двумя диапазонами. Вместо этого я бы передал две крайности диапазона в качестве отдельных аргументов.
  • используйте TreeNode класс для фактического создания деревьев, а затем займитесь созданием требуемого выходного формата.
  • Для генерации выходного формата вам нужен BFS-переход по дереву, и это может быть реализовано как метод на TreeNode .

Вот что, я думаю, сработает:

 class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

    def breadth_first(self):
        lst = []
        todo = [self]
        while any(todo):
            node = todo.pop(0)
            lst.append(node.val if node else None)
            if node:
                todo.append(node.left)
                todo.append(node.right)
        return lst

def generateTrees(n):
    def recur(start, end): # end is not included
        if start >= end:
            return [None]
        trees = []
        for root in range(start, end):
            lefts = recur(start, root)
            rights = recur(root 1, end)
            # Cartesian product:
            for left in lefts:
                for right in rights:
                    # Start with a new tree, and append to result
                    tree = TreeNode(root)
                    tree.left = left
                    tree.right = right
                    trees.append(tree)
        return trees
    return recur(1, n 1)

# Create the trees as a list of TreeNode instances:
trees = generateTrees(3)
# Convert to a list of lists 
print([tree.breadth_first() for tree in trees])