Какова среда выполнения моего рекурсивного запоминаемого решения

#algorithm #time-complexity #dynamic-programming #depth-first-search #space-complexity

Вопрос:

Я даю двоичное дерево поиска с n узлами с уникальным значением от 1 до n, и мне нужно вычислить, сколько структурно отличающихся двоичных деревьев поиска я могу сделать из него. Я использую DFS с запоминанием для решения проблемы. По сути, это похоже на то, что если у нас есть n узлов, корневой узел может быть от 1 до n, затем я рекурсивно вычисляю, сколько поддерево может иметь дерево. Кроме того, я запомнил диапазон значений узлов, которые может иметь дерево, и сколько разных деревьев можно создать с этим диапазоном значений узлов, поэтому я не пересчитываю. Я думаю, что время и пространство равны O (n ^ 2), поскольку для моего значения узла дерева может быть n ^ 2 разных диапазона. Кто-нибудь может прокомментировать это?

 class Solution {
    public int numTrees(int n) {
        
        // structrually unique BST with value from 1 to n
        // same structure but different number? no, one way to arrange node
        // from 1 to n start
        // left has num candid - 1 to 1
        // right has num candid   1 to n
        
        Map<Integer, Integer> memo = new HashMap<>();
        
        return numWays(1, n, memo);
    }
    
    
    private int numWays(int low, int high, Map<Integer, Integer> memo) {
        
        if(memo.containsKey(low * 100   high)) {
            return memo.get(low * 100   high);
        }
        
        if(low >= high) return 1;
        int ans = 0;
        for(int i = low; i <= high; i  ) {
            ans = ans   numWays(low, i - 1, memo) * numWays(i   1, high, memo);
        }
        memo.put(low * 100   high, ans);
        return ans;
    }
}

 

Ответ №1:

Временная сложность в настоящее время равна O (n ^ 3). Верно, что существует только O (n ^ 2) диапазонов и не более O (n ^ 2) пар (low, high), отображаемых в качестве входных данных для функции numWays. Однако функция numWays выполняет O (high-low 1) шагов после запоминания, что является еще одним фактором O (n).

Чтобы ускорить этот процесс, можно заметить, что количество по британскому летнему времени за [1,2,3,4] такое же, как и число по британскому летнему времени за [2,3,4,5] или [3,4,5,6]; только длина массива вопросам (дает вам o(п^2) алгоритм, с небольшим изменением). Другое возможное ускорение происходит от замечая, что за каждое двоичное корневое дерево с n узлами, существует ровно один способ обозначить узлы [1,2,…,N], можно получить по британскому летнему времени, значит, ты ищешь способ/повторение, чтобы рассчитывать корни бинарных деревьев.

Ответ №2:

Мы также могли бы использовать формулу:

 const f = n => n < 2 ? 1 : (4*n - 2) / (n   1) * f(n - 1);

for (let i=0; i<20; i  )
  console.log(f(i)); 

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

1. Хорошая формула. Было бы здорово иметь несколько слов, объясняющих, что для них uninitiates требуется? 😉 (голос 1)

2. @DanielHao я согласен, именно поэтому я ссылался на подробные объяснения в Википедии.