Простое решение:
class AccessGroupName { ... }
class Order { ... }
Map<AccessGroupName, Collection<Order>> visibility = new HashMap<AccessGroupName, Collection<Order>>();
addVisibility(AccessGroupName group, Order order) {
Collection<Order> orders = visibilities.get(group);
if (orders == null) {
orders = new ArrayList<Order>();
visibility.put(group, orders);
}
if (!orders.contains(order)) orders.add(order);
}
public Set<Order> getVisibility(Collection<AccessGroupName> names) {
Set<Order> visible = new HashSet<Order>();
for (AccessGroupName name: names) {
visible.addAll(visibilities.get(name));
}
return visible;
}
HashMap ищет O (1). Итерирование ArrayList - это O (n). Добавление элементов в HashSet - O (n). В целом, это будет O (n), где n - это общее количество элементов в добавленных списках (которое может быть больше, чем количество элементов в результирующем наборе, если есть наложение). Константа - это, примерно, время, необходимое для получения элемента из итератора ArrayList, плюс время, необходимое для добавления чего-либо в HashSet - первое порядка 10 циклов, второе ближе к 100.
Использование памяти сверх самих экземпляров AccessGroupName и Order составляет около 14-15 слов на группу плюс 1-2 слова на заказ. Главным образом заголовки объекта.
Этот код не делает ничего умного, но я думаю, что вам будет довольно трудно победить O (n) с константой <200 циклов. </p>
В частности, если условная матрица является разреженной (то есть, если есть много групп доступа с несколькими заказами в каждой), это отбросит штаны от подхода с битами, что приведет к потере чертовски много места по нулям, а время по нулям ИЛИ вместе.