Я пытаюсь создать коллекцию из всех возможных возможных комбинаций из 2-х возможных вариантов списка N. Длина коллекции будет отображать количество элементов в комбинации к упорядоченному списку комбинаций, содержащих комбинации определенной длины. Например, для списка:Java - сгенерируйте набор питания для данного списка
[A, B, C, D]
Я хочу, чтобы создать карту:
{
1 -> [{A}, {B}, {C}, {D}]
2 -> [{A, B}, {A, C}, {A, D}, {B, C}, {B, D}, {C, D}]
3 -> [{A, B, C}, {A, B, D}, {A, C, D}, {B, C, D}]
4 -> [{A, B, C, D}]
}
Сформированная база данных должна поддерживать первоначальный порядок (где []
представляет собой упорядоченный ряд (List
), и {}
представляет неупорядоченная группа (Set
)) и выполняться как можно быстрее.
Я боролся с каким-то рекурсивным кодом весь день (я знаю, что реализация должна быть рекурсивной), но не могла добраться до нее.
Есть ли ссылка, которую я могу использовать/готовую реализацию такого алгоритма?
UPDATE:
Благодаря предыдущим ответам, я придумал следующую реализацию:
public class OrderedPowerSet<E> {
private static final int ELEMENT_LIMIT = 12;
private List<E> inputList;
public int N;
private Map<Integer, List<LinkedHashSet<E>>> map =
new HashMap<Integer, List<LinkedHashSet<E>>>();
public OrderedPowerSet(List<E> list) {
inputList = list;
N = list.size();
if (N > ELEMENT_LIMIT) {
throw new RuntimeException(
"List with more then " + ELEMENT_LIMIT + " elements is too long...");
}
}
public List<LinkedHashSet<E>> getPermutationsList(int elementCount) {
if (elementCount < 1 || elementCount > N) {
throw new IndexOutOfBoundsException(
"Can only generate permutations for a count between 1 to " + N);
}
if (map.containsKey(elementCount)) {
return map.get(elementCount);
}
ArrayList<LinkedHashSet<E>> list = new ArrayList<LinkedHashSet<E>>();
if (elementCount == N) {
list.add(new LinkedHashSet<E>(inputList));
} else if (elementCount == 1) {
for (int i = 0 ; i < N ; i++) {
LinkedHashSet<E> set = new LinkedHashSet<E>();
set.add(inputList.get(i));
list.add(set);
}
} else {
list = new ArrayList<LinkedHashSet<E>>();
for (int i = 0 ; i <= N - elementCount ; i++) {
@SuppressWarnings("unchecked")
ArrayList<E> subList = (ArrayList<E>)((ArrayList<E>)inputList).clone();
for (int j = i ; j >= 0 ; j--) {
subList.remove(j);
}
OrderedPowerSet<E> subPowerSet =
new OrderedPowerSet<E>(subList);
List<LinkedHashSet<E>> pList =
subPowerSet.getPermutationsList(elementCount-1);
for (LinkedHashSet<E> s : pList) {
LinkedHashSet<E> set = new LinkedHashSet<E>();
set.add(inputList.get(i));
set.addAll(s);
list.add(set);
}
}
}
map.put(elementCount, list);
return map.get(elementCount);
}
}
Я был бы рад получить обратную связь для способов, чтобы улучшить это.
UPDATE 2:
Я установил несколько вопросов в коде и тестировал.
Я не уверен, что рекурсия особенно полезна для этой проблемы. Подумайте об этом итеративно вместо этого. –
Если вы делаете это итеративно, обратите внимание, что вы можете одновременно генерировать списки размером 'i' и size' N-i'. Подумайте о разбиении списка на два подмножества и добавлении каждого подмножества в один из ваших списков результатов. –
Это интересный подход, я рассмотрю его. – Elist