Я бы не стал придавать большое значение процентам LeetCode.Когда я отправляю ваше рекурсивное решение, оно показывает, что оно превышает 34%.LeetCode также показывает точно такой же пример кода для сегментов 100% и 34%.Можно только догадываться, каковы их тестовые случаи.Все реализации, которые я представил, выполняются за 1 мс, так что, скорее всего, все 41 из их тестовых случаев - очень маленькие деревья, так что различия в производительности совершенно незначительны.Вы также не знаете, какие древовидные структуры преобладают в примерах - все они могут быть более или менее сложными по времени, и в этом случае BFS имеет небольшое преимущество или вообще не имеет его над DFS.
При этомпомните, давайте оценим ваш код на больших тестовых примерах, чтобы увидеть, сможем ли мы получить некоторое понимание, которого нельзя достичь в среде тестирования черного ящика, которую предлагает LeetCode.
Прежде чем мы это сделаем, давайте рассмотрим вашу BFSрешение, которое использует рекурсию и манипулирует ArrayList, как если бы это была очередь.Это правда, что операции сдвига ArrayList амортизируются O (1), но использование ArrayDeque является гораздо более быстрой и более семантически подходящей структурой данных для операций с очередями в Java.
Кроме того, используя рекурсию в своей реализации BFS, вывы отрицаете одно из основных преимуществ BFS, заключающееся в том, что оно итеративное.Отсутствие необходимости манипулировать стеком вызовов должно значительно сократить накладные расходы.
Сложив все это вместе, я написал бы функцию BFS следующим образом:
public int minDepth(TreeNode root) {
ArrayDeque<Pair<TreeNode, Integer>> q = new ArrayDeque<>();
q.offer(new Pair(root, 1));
while (!q.isEmpty()) {
Pair<TreeNode, Integer> curr = q.poll();
if (curr.first != null) {
if (curr.first.left == null && curr.first.right == null) {
return curr.second;
}
q.offer(new Pair(curr.first.left, curr.second + 1));
q.offer(new Pair(curr.first.right, curr.second + 1));
}
}
return 0;
}
Теперь быстрый тест.Здесь BFS2
- ваша реализация BFS, а BFS
- моя:
long BFSTotal = 0;
long BFS2Total = 0;
long DFSTotal = 0;
for (int i = 0; i < 10000; i++) {
TreeNode root = randomTree(10000);
long start = System.currentTimeMillis();
minDepthDFS(root);
DFSTotal += System.currentTimeMillis() - start;
start = System.currentTimeMillis();
minDepthBFS(root);
BFSTotal += System.currentTimeMillis() - start;
start = System.currentTimeMillis();
minDepthBFS2(root);
BFS2Total += System.currentTimeMillis() - start;
}
System.out.println("BFS: " + BFSTotal);
System.out.println("BFS2: " + BFS2Total);
System.out.println("DFS: " + DFSTotal);
Этот код создает 10000 различных деревьев, каждое с 10000 узлами, созданными с использованием алгоритма броска монеты, и запускает алгоритмы для каждого дерева.,Вот результаты нескольких прогонов:
BFS: 1906
BFS2: 5484
DFS: 3351
BFS: 1709
BFS2: 6101
DFS: 3773
BFS: 1527
BFS2: 5567
DFS: 3856
Продолжайте и запустите код самостоятельно и немного поэкспериментируйте.Я не думаю, что эти результаты являются абсолютно убедительными, но они укрепляют мои основные предпосылки: BFS превосходит DFS из-за меньших накладных расходов и потенциала для раннего освобождения (в худшем случае сложности времени одинаковы), а нерекурсивная реализация BFS используетэффективная структура данных превосходит рекурсивную реализацию BFS, которая использует неэффективную структуру данных.
Это также демонстрирует, что ваша реализация BFS примерно в два раза медленнее, чем ваша реализация DFS, что может объяснить ваши результаты LeetCodeно, опять же, я бы не решился сделать какие-либо выводы, учитывая, насколько крошечными кажутся их тестовые случаи.