Хорошо, давайте попробуем решить задачу, не выполняя ее фактически:)
Грубо говоря, алгоритм выглядит следующим образом:
Взять целое число x
из исходного списка
Если целевой список списков (каждый из которых содержит целые числа одного и того же класса эквивалентности) содержит список соответствующего класса эквивалентности, добавьте x
в этот список
В противном случае создайте новый список классов эквивалентности, содержащий одно значение ([x]
), и добавьте его в целевой список
Повтор 1- 3 для других целых чисел в списке целей.
(1), (3) и (4) представляется довольно тривиальным для реализации.
Проблемы как реализовать (2) и как это сделать эффективно:)
«Целевой список содержит список, который ...» можно перефразировать как «существует список lst
в целевом списке, например. .. "- это дает нам сильный намек на то, что List.exists
можно как-то здесь использовать. Что проверять, также более или менее ясно: каждый член одного и того же списка классов эквивалентности по определению эквивалентен, поэтому мы можем взять только голову и сравнить ее с x
, используя p
.
Вопрос как добавить целое число в список в другом списке. Списки неизменны, поэтому мы не можем просто удалить их там ... Но мы можем взять список целей и преобразовать или свернуть в другой. Могу поспорить, что вы получили подсказку: List.fold_left
- еще одна часть головоломки.
Итак, суммируя все это, мы можем прийти к следующему «более точному» алгоритму
Начните с пустого списка целей res
Возьмите целое число x
из списка источников l
Используйте List.exists
чтобы проверить, есть ли список lst
в res
, например, для его головы h
p x h = true
Если да, используйте List.fold_left
для преобразования тока res
в новый, где lst
заменен на x::lst
, а все остальные списки классов эквивалентности скопированы как
Если нет, введите новый класс эквивалентности (добавьте [x]
до res
)
Повторите 2-5 для следующего целого числа в списке источников, пока оно не станет пустым.
Реализация, которая (почти) буквально следует этому алгоритму относительно просто. Но это будет не очень эффективно, потому что exists
и fold
будут повторять один и тот же список дважды, выполняя буквально одну и ту же проверку. С некоторыми изменениями можно было бы сделать это за один проход, но этот неэффективный должен быть достаточно хорошим в качестве отправной точки ...