Комбинация списка списков, так что каждая комбинация имеет уникальные элементы
Итак, у меня есть список списков, как говорит заголовок, и я хочу сделать комбинации из k списков, в которых каждый список имеет элементы, отличные от остальных.
Пример:
У меня есть следующий список списков:
{ {1,2,3} , {1,11} , {2,3,6} , {6,5,7} , {4,8,9} }
Допустимая 3-размерная комбинация этих списков может быть:
{ {1,11}, {4,8,9} ,{6,5,7} }
Это только ОДНА из допустимых комбинаций, я хочу вернуть список всех допустимых комбинаций из K списков.
Недопустимая комбинация будет:
{ {1,11} ,{2, 3, 6}, {6, 5, 7} }
потому что элемент 6 присутствует во втором и третьем списке.
У меня уже есть код, который делает это, но он просто находит все возможные комбинации и проверяет их действительность, прежде чем добавить его в список окончательных результатов. Поскольку этот список списков довольно велик (153 списка), когда K становится больше, время, потраченное на него, тоже смехотворно велико (при K = 5 это занимает у меня около 10 минут).
Я хочу посмотреть, есть ли эффективный способ сделать это. Ниже мой текущий код (списки, которые я хочу объединить, являются атрибутом класса Item):
public void recursiveComb(List<Item> arr, int len, int startPosition, Item[] result)
{
if (len == 0)
{
if (valid(result.ToList()))
{
//Here I add the result to final list
//valid is just a function that checks if any list has repeated elements in other
}
return;
}
for (int i = startPosition; i <= arr.Count - len; i++)
{
result[result.Length - len] = arr[i];
recursiveComb(arr, len - 1, i + 1, result);
}
}
3 ответа
Если я правильно понял ваш код, то вы передаете каждый list<int>
от вашего вклада в recursiveComb()
функция. которые выглядят так
for(int i = 0; i < inputnestedList.Count; i++)
{
recursiveComb();
// Inside of recursiveComb() you are using one more for loop with recursion.
// This I observed from your first parameter i.e. List<int>
}
Поправьте меня если я не прав
Это приводит к сложности времени больше, чем O(n^2)
Вот мое самое простое решение, с двумя forloops без рекурсии.
List<List<int>> x = new List<List<int>>{ new List<int>(){1,2,3} , new List<int>(){1,11} , new List<int>(){2,3,6} , new List<int>(){6,5,7} , new List<int>(){4,8,9} };
List<List<int>> result = new List<List<int>>();
var watch = Stopwatch.StartNew();
for (int i = 0; i < x.Count;i++)
{
int temp = 0;
for (int j = 0; j < x.Count; j++)
{
if (i != j && x[i].Intersect(x[j]).Any())
temp++;
}
// This condition decides, that elements of ith list are available in other lists
if (temp <= 1)
result.Add(x[i]);
}
watch.Stop();
var elapsedMs = watch.Elapsed.TotalMilliseconds;
Console.WriteLine(elapsedMs);
Теперь, когда я печатаю время выполнения, вывод
Execution Time: 11.4628
Проверьте время выполнения вашего кода. Если время выполнения вашего кода выше, чем у меня, то вы можете считать его эффективным кодом
Доказательство кода: DotNetFiddler
Удачного кодирования
Если я правильно понял вашу проблему, то это будет работать:
/// <summary>
/// Get Unique List sets
/// </summary>
/// <param name="sets"></param>
/// <returns></returns>
public List<List<T>> GetUniqueSets<T>(List<List<T>> sets )
{
List<List<T>> cache = new List<List<T>>();
for (int i = 0; i < sets.Count; i++)
{
// add to cache if it's empty
if (cache.Count == 0)
{
cache.Add(sets[i]);
continue;
}
else
{
//check whether current item is in the cache and also whether current item intersects with any of the items in cache
var cacheItems = from item in cache where (item != sets[i] && item.Intersect(sets[i]).Count() == 0) select item;
//if not add to cache
if (cacheItems.Count() == cache.Count)
{
cache.Add(sets[i]);
}
}
}
return cache;
}
Протестировано, это быстро и заняло 00:00:00.0186033 для поиска наборов.
Используйте HashSet https://msdn.microsoft.com/en-us/library/bb359438(v=vs.110).aspx чтобы отслеживать отдельные элементы при создании вывода из кандидатов в списке ввода списков / кортежи
накапливать выходной список неперекрывающихся кортежей, перебирая входной список кортежей и оценивая каждый кортеж как кандидата следующим образом: Для каждого входного кортежа вставьте каждый элемент кортежа в HashSet. Если элемент, который вы пытаетесь вставить, уже находится в наборе, тогда кортеж не проходит ограничение и должен быть пропущен, в противном случае все элементы кортежа отличаются от тех, которые уже есть в выходных данных.
Объект hashset эффективно поддерживает реестр отдельных элементов в вашем принятом списке кортежей.