Алгоритмы с нуля
Рекурсия и backtracking: тест с множественным выбором
Шесть вопросов через весь юнит. Каждый — это решение, которое вы принимаете, когда реально пишете рекурсивный код: не определение для заучивания, а суждение о корректности, стоимости или о том, какое исправление верное.
Убедитесь, что вы связываете четыре идеи юнита: base case и сужающийся recursive case обеспечивают завершение рекурсии, call stack задаёт память, дерево рекурсии задаёт время, а backtracking с pruning превращает полный перебор в нечто практичное.
У рекурсивной функции есть base case, но она всё равно переполняет стек на любом входе, даже на крошечном. В чём наиболее вероятная причина?
factorial(n) и наивный fibonacci(n) оба рекурсируют до глубины n. Почему factorial нормален для больших n, а fibonacci нет?
У рекурсивной функции branching factor b = 3 и глубина d = 12, на вызов делается O(1) работы. Примерно сколько вызовов она делает и о чём это говорит?
В шаблоне backtracking choose-explore-undo что ломается, если опустить шаг undo (push в current, но никогда pop)?
Subsets, permutations и combinations используют один и тот же шаблон backtracking. Что на самом деле их различает?
Корректный рекурсивный обход дерева работает в тестах, но коллега говорит, что перед продакшеном его надо переписать итеративно. Когда это оправдано?
Сквозная линия юнита — одна цепочка: base case плюс сужающийся recursive case обеспечивают завершение рекурсии; call stack делает глубину стоимостью O(глубина) по памяти; дерево рекурсии делает общую работу равной branching factor в степени глубины по времени; а backtracking применяет этот рекурсивный скелет (choose, explore, undo) с pruning, чтобы пропускать обречённые ветки. Сначала верно задайте base case и прогресс, затем читайте время по дереву, а память — по стеку.