Рекурсивный подсчёт числа путей — рабочий код до большого n
Задача про количество путей в сетке (unique paths) или похожая на неё часто получает первое решение через прямую рекурсию: из клетки идём вправо или вниз, суммируем количество путей из обеих соседних клеток.
На маленькой сетке 5x5 такое решение отрабатывает мгновенно. Проблема в том, что рекурсия без мемоизации пересчитывает одни и те же подзадачи многократно — число вызовов растёт экспоненциально с размером сетки.
int countPaths(int row, int col) { if (row == 0 || col == 0) { return 1; } return countPaths(row - 1, col)
- countPaths(row, col - 1); }
На сетке 20x20 это уже сотни тысяч вызовов ради ответа, который вычисляется за один проход динамическим программированием снизу вверх, где каждая клетка считается один раз.
На собесе после такого решения спросят: какая сложность у рекурсии без кэша. Правильный ответ — экспоненциальная, O(2^(n+m)), потому что дерево вызовов не переиспользует поддерево дважды вычисленных клеток. Дальше попросят переписать через таблицу dp[row][col] с накоплением суммы соседних клеток, либо через мемоизацию с кэшем по паре координат.
Прямая рекурсия для задач на сетке — почти всегда сигнал, что дальше попросят посчитать сложность и переписать на dp.
Тренажёр: 600 вопросов, мок с таймером, план повторов
senior·base — что спрашивают на самом деле
В этом посте были ссылки, но мы их удалили по правилам Сетки