Поскольку язык программирования не упоминается, я предполагаю, что списки тоже в порядке. Итак, вот версия OCaml, подходящая для коротких списков (без хвостовой рекурсии). При наличии списка l элементов любого типа и целого числа n будет возвращен список всех возможные списки, содержащие n элементов l , если предположить, что порядок элементов в списках результатов игнорируется, т.е. list [ 'a'; 'b'] совпадает с ['b'; 'a'] и будет сообщено один раз. Таким образом, размер результирующего списка будет ((List.length l) Выберите n).
Интуиция рекурсии заключается в следующем: вы берете верхнюю часть списка и затем делаете два рекурсивных вызова:
- рекурсивный вызов 1 (RC1): в конец списка, но выберите n-1 элементов
- рекурсивный вызов 2 (RC2): в конец списка, но выберите n элементов
, чтобы объединить рекурсивные результаты, умножьте список (укажите нечетное имя) на начало списка с результатами RC1, а затем добавьте (@) результаты RC2. Умножение списка - это следующая операция lmul
:
a lmul [ l1 ; l2 ; l3] = [a::l1 ; a::l2 ; a::l3]
lmul
реализовано в приведенном ниже коде как
List.map (fun x -> h::x)
Рекурсия прекращается, когда размер списка равен количеству элементов, которые вы хотите выбрать, и в этом случае вы просто возвращаете сам список.
Итак, вот четыре строки в OCaml, которые реализуют вышеуказанный алгоритм:
let rec choose l n = match l, (List.length l) with
| _, lsize when n==lsize -> [l]
| h::t, _ -> (List.map (fun x-> h::x) (choose t (n-1))) @ (choose t n)
| [], _ -> []