Как найти подмножество с наибольшим количеством общих элементов? - PullRequest
2 голосов
/ 21 января 2012

Допустим, у меня есть несколько «известных» наборов:

1 {a, b, c, d, e}
2 {b, c, d, e}
3 {a, c, d}
4 {c, d}

Мне нужна функция, которая принимает набор в качестве входных данных (например, {a, c, d, e}) и находит набор, который имеет наибольшее количество элементов, и не имеет других общих элементов. Другими словами, подмножество с наибольшим количеством элементов. Ответ не должен быть правильным подмножеством. Ответ в этом случае будет {a, c, d}.

РЕДАКТИРОВАТЬ: приведенный выше пример был неправильным, теперь исправлено.

Я пытаюсь найти самый эффективный способ сделать это.

(Ниже я предполагаю, что стоимость сравнения двух наборов O (1) ради простоты. Эта операция вне моего контроля, поэтому нет смысла думать об этом. Правда, это будет зависеть от мощности двух сравниваемых множеств.)

Кандидат 1:

Генерация всех подмножеств ввода, затем итерация по известным наборам и возвращение наибольшего, которое является подмножеством. Недостатком этого является то, что сложность будет примерно равна O (n! & Times; m ), где n - количество элементов входного набора, а m количество «известных» подмножеств.

Кандидат 1a (спасибо @bratbrat):

Переберите все «известные» множества и вычислите мощность пересечения, и возьмите тот, который имеет наибольшее значение. Это будет O (n) , где n - количество подмножеств.

Кандидат 2:

Создать обратную таблицу и вычислить евклидово расстояние между входом и известными наборами. Это может быть довольно быстро. Я не понимаю, как я мог ограничить это, чтобы включить только подмножества без последующего фильтра O (n) .

Кандидат 3:

Переберите все известные множества и сравните с входными данными. Сложность будет O (n) , где n - количество известных наборов.

В моем распоряжении набор функций, встроенных в Python и Redis.

Ничто из этого не кажется особенно великим. Идеи? Количество наборов может быть большим (около 100 000 в расчете).

Ответы [ 3 ]

1 голос
/ 21 января 2012

Невозможно сделать это менее чем за O (n) время ... просто чтение ввода - это O (n).

Пара идей:

Сортировка наборов по размеру (по возрастанию) и поиск первого набора, который является подмножеством входного набора. Как только вы найдете один, вам не нужно проверять остальные.

Если количество возможных элементов, которые могут быть в наборах, ограничено, вы можете представить их с помощью битовых векторов. Затем вы можете рассчитать таблицу поиска, чтобы сказать вам, является ли данный набор подмножеством входного набора. (Идите вниз по битам для каждого рассматриваемого набора входов, слово за словом, индексируя каждое слово в соответствующую таблицу. Если вы найдете запись, сообщающую, что это не подмножество, вы снова можете перейти непосредственно к следующему набору входов. Будет ли это на самом деле покупать производительность, зависит от языка реализации. Я полагаю, что это было бы наиболее эффективно в языке с примитивными целочисленными типами, такими как C или Java.

0 голосов
/ 22 января 2012

Сколько поисков вы делаете? Если вы ищете несколько входных наборов, у вас должна быть возможность предварительно обработать все известные наборы (возможно, в виде древовидной структуры), и ваше время поиска для каждого запроса будет в порядке размера вашего набора запросов.

Например: создать структуру Trie со всеми известными наборами. Обязательно сортируйте каждый набор перед тем, как вставлять их. Для запроса перейдите по ссылкам в наборе.

0 голосов
/ 21 января 2012
  1. Возьмите объединение известных множеств.Это становится словарем известных элементов.
  2. Сортировка известных элементов по их значению (они целые, верно).Это определяет позицию данного целого числа в битовой строке.
  3. Используйте вышеприведенное для определения битовых строк для каждого из известных наборов.Это однократная операция - результаты должны быть сохранены во избежание повторного вычисления.
  4. Для входного набора выполните его через то же преобразование, чтобы получить его битовую строку.
  5. Чтобы получить наибольшее подмножество, пропустите список известных битовых строк, взяв пересечение (логическое и) с входной битовой строкой.Подсчитайте элементы «1».Вспомните самый большой из них.

http://packages.python.org/bitstring

Как уже упоминалось в комментариях, это можно распараллелить, подразделив известные наборы и предоставив каждому потоку свое собственное подмножество для работы.Каждый поток подает свое лучшее соответствие, а затем родительский поток выбирает лучшее из потоков.

...