Как создать декартово произведение над произвольными группами чисел в Java?
предположим, у меня есть 2 группы чисел:
{1, 2, 3},
{4, 5}
Я хотел бы создать алгоритм (на Java), который выводит следующие 6 комбинаций:
1,4
1,5
2,4
2,5
3,4
3,5
в каждой группе может быть произвольное количество групп и произвольное количество членов. Таким образом, в приведенном выше примере есть 2 группы с первой группой, имеющей 3 члена, и второй группой, имеющей 2 члена. Другим примером является следующее (3 группы, 3 члена в первых группах и 2 члена в вторая и третья группы):
{1, 2, 3},
{4, 5},
{6, 7}
что дало бы следующие 12 комбинаций:
1,4,6
1,4,7
1,5,6
1,5,7
2,4,6
2,4,7
2,5,6
2,5,7
3,4,6
3,4,7
3,5,6
3,5,7
как я могу сделать это в Java? Я пытаюсь использовать рекурсию, и я посмотрел на аналогичный вопрос уже, но мне все еще не хватает. Спасибо за помощь! (P. S. Это не домашнее задание)
4 ответов
немного заскучал и решил попробовать. Должно быть именно то, что вам нужно:
public static void main(String args[]) {
ArrayList<int[]> input = new ArrayList<int[]>();
input.add(new int[] { 1, 2, 3 });
input.add(new int[] { 4, 5 });
input.add(new int[] { 6, 7 });
combine(input, new int[input.size()], 0);
}
private static void combine(ArrayList<int[]> input, int[] current, int k) {
if(k == input.size()) {
for(int i = 0; i < k; i++) {
System.out.print(current[i] + " ");
}
System.out.println();
} else {
for(int j = 0; j < input.get(k).length; j++) {
current[k] = input.get(k)[j];
combine(input, current, k + 1);
}
}
}
Если вы можете использовать библиотеки, гуава это Sets.cartesianProduct(List<Set<E>>)
тут ровно то, что вы ищете. (Раскрытие: я вношу свой вклад в гуаву.)
один из возможных подходов (не обязательно самый эффективный) может заключаться в подходе "разделяй и властвуй". Относительно просто найти все перестановки двух групп (самый тупой способ просто вложен для циклов). Допустим, вы пишете функцию permute
и это permute(A,B)
где A (например {(1), (2), (3)}) и B(например, {(4), (5)} - группы чисел, и он возвращает вам все перестановки A & B как одну группу (e.g {(1,4), (1,5), (2,4), (2,5), (3,4), (3,5)}).
поэтому, когда у вас есть N групп вместо 2, проще всего просто выбрать небольшие части проблемы. Предположим, у вас есть группы A, B и C. Вместо того, чтобы беспокоиться о них всех отдельно, вы можете думать об этом как о чем-то вроде:
permute(permute(A,B),C)
сначала найдите все перестановки A и B. Как только у вас есть этот результат, найдите все перестановки этого результата с C. и четыре группы A, B, C, D могут выглядеть например:
permute(permute(permute(A,B),C),D)
и так далее. На каждом шаге по пути вы берете текущий результат перестановки и переставляете его со следующей группой в списке групп, которые вы получили в качестве входных данных. Вы объединяете только две группы одновременно, поэтому алгоритм не должен меняться в зависимости от количества групп, которые вы получаете в качестве входных данных.
когда вы делаете рекурсию, есть несколько основных вопросов, на которые вам нужно ответить:
вы можете рекурсивно разбить проблему на меньшие, более разрешимые проблемы? Я думаю, что приведенные выше примеры доказывают, что можно.
Что такое базовый? Каково решение, которое приведет к остановке и размотке рекурсии? Как правило, это должно быть что-то очень простое, к чему может работать ваша рекурсия. В этом случае, вероятно, сводится к чему-то вроде
permute(A,{})
где {} - пустой набор.Что такое рекурсивный случай? Как вы оторвете кусок проблемы и обратиться на меньшем подмножестве проблема? Я думаю, что первоначальное объяснение дает вам один способ потенциально сделать это. Просто отрывайтесь от одной группы за раз и перемежайте ее своим постоянно растущим результатом.
конечно, есть и другие решения этой проблемы, это только первое, что пришло мне в голову. Как N становится больше и больше, этот алгоритм будет существенно замедлен, так как это не очень эффективный.
так что даже если вы не используете это решение, я надеюсь, что это получает Вы на правильном пути!
Как насчет следующего псевдо-кода (без рекурсии)
// Create the initial result filled with the first set of numbers
List result = new List()
For each number in the first set
result.add(new List(number))
// Iterate over the following sets to permutate over
For each remaining set S
List newResult = new List()
For each list L in result
For each number N in S
newResult.add(copy of L with N added)
result = newResult