Ваш ввод - это список списков списков (и т. Д.), Также известный как деревья.
Вы хотите вычислить самую длинную длину одного из списков, составляющих дерево. Грубо говоря, вам нужно перебрать поддеревья, вычислить их наибольшую длину и объединить их в новую максимальную длину.
Первый эскиз функции выглядит следующим образом на основе макроса LOOP (вам еще нужно немного поработать, чтобы преобразовать его в полностью рекурсивное решение):
(defun longest-length (tree)
(loop for subtree in tree maximize (longest-length subtree)))
Как описано выше, вы делите свои проблемы на подзадачи, рекурсивно решаете их, находя
для каждого поддерева их наибольшая длина, и объединить их, возвращая
максимум каждого локального максимума.
Но в вышесказанном не хватает пары вещей. Во-первых, вы должны принять во внимание, что длина самого дерева должна быть вычислена:
(defun longest-length (tree)
(max (length tree)
(loop for subtree in tree maximize (longest-length subtree))))
Кроме того, код завершается ошибкой, когда достигает элементов, которые не являются ячейками.
Теперь вам нужно добавить код для базового случая, когда деревья не являются cons-ячейками. В частности, ноль рассматривается как пустые списки, а не как символ:
(defun longest-length (tree)
(typecase tree
(cons (max (length tree)
(loop
for subtree in tree
maximize (longest-length subtree))))
(null 0)
(t 1)))
Вот тест:
CL-USER> (longest-length '(1 (2 (3 (4 5 a a a a)) (6 7) 8) 9))
6
Также рассмотрите возможность использования reduce
, который, в отличие от apply
, не вводит ограничений на количество элементов в списке (call-argument-limit
):
(reduce #'max (mapcar ... tree) :initial-value (length tree))