Создание всех мультимножеств подмножеств значений NON DISTINCT в Java - PullRequest
0 голосов
/ 06 октября 2018

Учитывая массив объектов, мне нужно как можно более эффективно найти все различные наборы подмножеств данного массива, которые включают все значения, когда значения в массиве могут повторяться.

дляпример: если массив 1, 2, 1, 2, то мне нужно создать следующие мультимножества:

  1. {[1], [1], [2], [2]}
  2. {[1], [1], [2, 2]}
  3. {[1], [2], [1, 2]}
  4. {[1], [1, 2, 2]}
  5. {[1, 1], [2], [2]}
  6. {[1, 1], [2, 2]}
  7. {[1, 2], [1, 2]}
  8. {[1, 1, 2], [2]}
  9. {[1, 1, 2, 2]}

Обратите внимание, что ни порядок значений внутри подмножества, ни порядок подмножеств внутри мультимножества не имеют значения.Мультимножество, например {[1, 2, 2], [1]}, совпадает с #4, в то время как {[2, 1], [2], [1]} совпадает с #3.

. Пример здесь был с целыми числами, но на практике мне придется делать это собъекты.

Это должно быть максимально эффективно.Лучше всего будет вычислять только правильные (неповторяющиеся) мультимножества, без какой-либо проверки, если он уже появился, потому что способ его создания устранит это из-за возникновения.

Я знаю, как создать все подмножества с использованием двоичного файла.представление.Я использовал это в сочетании с рекурсией для вычисления всех мультимножеств.Это работает отлично, за исключением того, что не работает, когда значения повторяются.Вот что я сделал до сих пор:

( a - массив заданных чисел, curr - текущий мультисет, который создается, и b - окончательный набор всех мультимножеств.)

public static void makeAll(ArrayList<Integer> a, 
                           ArrayList<ArrayList<Integer>> curr,
                           ArrayList<ArrayList<ArrayList<Integer>>> b) {

    ArrayList<ArrayList<Integer>> currCopy;
    ArrayList<Integer> thisGroup, restGroup;
    int currSize = 0, ii = 0;

    if (a.size() == 0)
        b.add(new ArrayList<ArrayList<Integer>>(curr));
    else {
        for (int i = 0; i < 1 << (a.size() - 1); i++) {
            thisGroup = new ArrayList<>();
            restGroup = new ArrayList<>();
            ii = (i << 1) + 1; // the first one is always in, keeps uniquness.

            for (int j = 0; j < a.size(); j++)
                if ((ii & 1 << j) > 0)
                    thisGroup.add(a.get(j));
                else
                    restGroup.add(a.get(j));

            currSize = curr.size();
            curr.add(new ArrayList<Integer>(thisGroup));

            makeAll(restGroup, curr, b);

            curr.subList(currSize, curr.size()).clear();
        }
    }
}

Заранее спасибо!

1 Ответ

0 голосов
/ 06 октября 2018

Это проблема «набора мощности», с более чем двумя обычными наборами (которые обычно либо включаются, либо исключаются из подмножества, следовательно, набор питания имеет 2 ^ N элементов).Для вашей версии этой проблемы любой элемент может быть частью любого из N подмножеств, поэтому проблема масштабируется как N ^ N (который очень быстро увеличивается).

Чтобы найти все уникальные разбиения вПри этом "N-way power set", учитывая список из N элементов, вам нужно концептуально сгенерировать все N-значные числа в базе N, тогда значение каждой цифры числа дает индекс разделения для соответствующего элемента на входе (это означает, что обычно вы получите пустые разделы для всех случаев, кроме случаев, когда количество разделов равно N).Используйте эти цифровые индексы для группировки элементов в списки элементов с одинаковым индексом, создавая список списков.Для обнаружения дубликатов необходимо отсортировать подсписки, а затем отсортировать список списков, а затем добавить отсортированный список списков в набор.Вы не можете избежать этого последнего шага дедупликации, так как ваше описание допускает дублирование элементов во входных данных.

package main;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class PrintPartitionings {
    /** A list of integers */
    public static class Partition extends ArrayList<Integer>
            implements Comparable<Partition> {
        // Lexicographic comparator
        @Override
        public int compareTo(Partition other) {
            for (int i = 0, ii = Math.min(this.size(),
                    other.size()); i < ii; i++) {
                int c = this.get(i).compareTo(other.get(i));
                if (c != 0) {
                    return c;
                }
            }
            return Integer.compare(this.size(), other.size());
        }
    }

    /** A list of lists of integers */
    public static class Partitioning extends ArrayList<Partition>
            implements Comparable<Partitioning> {
        public Partitioning() {
            super();
        }

        public Partitioning(int N) {
            super(N);
            // Pre-allocate sub-lists for convenience
            for (int j = 0; j < N; j++) {
                add(new Partition());
            }
        }

        // Lexicographic comparator
        @Override
        public int compareTo(Partitioning other) {
            for (int i = 0, ii = Math.min(this.size(),
                    other.size()); i < ii; i++) {
                int c = this.get(i).compareTo(other.get(i));
                if (c != 0) {
                    return c;
                }
            }
            return Integer.compare(this.size(), other.size());
        }
    }

    /** Print all unique partitionings of the passed array of integers */
    public static void printPartitionings(int[] elts) {
        int N = elts.length;
        Set<Partitioning> setOfPartitionings = new HashSet<>();
        // Generate integers in [0, N^N)
        for (long i = 0, ii = (long) Math.pow(N, N); i < ii; i++) {
            // Create empty partitioning
            Partitioning partitioning = new Partitioning(N);

            // Assign each element to a partition based on base N digit
            long digits = i;
            for (int j = 0; j < N; j++) {
                int digit = (int) (digits % N);
                digits /= N;
                partitioning.get(digit).add(elts[j]);
            }

            // Sort individual partitions, and remove empty partitions
            Partitioning partitioningSorted = new Partitioning();
            for (Partition partition : partitioning) {
                if (!partition.isEmpty()) {
                    Collections.sort(partition);
                    partitioningSorted.add(partition);
                }
            }

            // Sort the partitioning
            Collections.sort(partitioningSorted);

            // Add the result to the final set of partitionings
            setOfPartitionings.add(partitioningSorted);
        }

        // Sort lexicographically to make it easier to view the result
        List<Partitioning> setOfPartitioningsSorted = new ArrayList<>(
                setOfPartitionings);
        Collections.sort(setOfPartitioningsSorted);
        for (Partitioning partitioning : setOfPartitioningsSorted) {
            System.out.println(partitioning);
        }
    }

    public static void main(String[] args) {
        printPartitionings(new int[] { 1, 2, 1, 2 });
    }
}

Реализация не особенно оптимизирована - это можно сделать быстрее несколькими способами.Кроме того, приведенный код будет работать только для задач среднего размера, когда N ^ N <<code>Long.MAX_VALUE, т.е. максимальное значение N равно 15 для кода, как показано (но вы все равно не захотите запускать задачи такого размера, поскольку выполнение кода будет длиться вечно).

Вывод:

[[1], [1], [2], [2]]
[[1], [1], [2, 2]]
[[1], [1, 2], [2]]
[[1], [1, 2, 2]]
[[1, 1], [2], [2]]
[[1, 1], [2, 2]]
[[1, 1, 2], [2]]
[[1, 1, 2, 2]]
[[1, 2], [1, 2]]

Для ввода { 1, 2, 3, 2 } вывод:

[[1], [2], [2], [3]]
[[1], [2], [2, 3]]
[[1], [2, 2], [3]]
[[1], [2, 2, 3]]
[[1, 2], [2], [3]]
[[1, 2], [2, 3]]
[[1, 2, 2], [3]]
[[1, 2, 2, 3]]
[[1, 2, 3], [2]]
[[1, 3], [2], [2]]
[[1, 3], [2, 2]]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...