Как рассчитать комбинации n элементов без повторений [дубликат]

Мне интересно, когда использовать статические методы?

blockquote>
  1. Общим методом использования для static методов является доступ к полям static.
  2. Но вы можете иметь методы static, не ссылаясь на переменные static. Вспомогательные методы без ссылки на переменную static можно найти в некоторых Java-классах, таких как java.lang.Math
    public static int min(int a, int b) {
        return (a <= b) ? a : b;
    }
    
  3. В другом случае использования, я могу думать об этих методах вместе с synchronized метод - это реализация блокировки уровня класса в многопоточной среде.

Скажите, есть ли у меня класс с несколькими геттерами и сеттерами, метод или два, и я хочу, чтобы эти методы были только invokable для объекта экземпляра класса. Означает ли это, что я должен использовать статический метод?

blockquote>

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

Документация Oracle страница содержит более подробную информацию.

Не все комбинации переменных и методов экземпляра и класса разрешены:

  1. Методы экземпляров могут напрямую обращаться к переменным экземпляра и методам экземпляра.
  2. Методы экземпляра могут напрямую обращаться к переменным класса и методам класса.
  3. Методы класса могут напрямую обращаться к переменным класса и методам класса.
  4. Методы класса не могут напрямую обращаться к переменным экземпляра или методам экземпляра - они должны использовать объект Справка. Кроме того, методы класса не могут использовать это ключевое слово, поскольку для этого не существует экземпляра.
25
задан Peter O. 18 April 2013 в 18:29
поделиться

9 ответов

Это O (n!) [/ ​​g0]

static List<List<int>> comb;
static bool[] used;
static void GetCombinationSample()
{
    int[] arr = { 10, 50, 3, 1, 2 };
    used = new bool[arr.Length];
    used.Fill(false);
    comb = new List<List<int>>();
    List<int> c = new List<int>();
    GetComb(arr, 0, c);
    foreach (var item in comb)
    {
        foreach (var x in item)
        {
            Console.Write(x + ",");
        }
        Console.WriteLine("");
    }
}
static void GetComb(int[] arr, int colindex, List<int> c)
{

    if (colindex >= arr.Length)
    {
        comb.Add(new List<int>(c));
        return;
    }
    for (int i = 0; i < arr.Length; i++)
    {
        if (!used[i])
        {
            used[i] = true;
            c.Add(arr[i]);
            GetComb(arr, colindex + 1, c);
            c.RemoveAt(c.Count - 1);
            used[i] = false;
        }
    }
}
11
ответ дан gunr2171 18 August 2018 в 12:55
поделиться
  • 1
    Хотя этот фрагмент кода может решить вопрос, , включая объяснение , действительно помогает улучшить качество вашего сообщения. Помните, что вы отвечаете на вопрос читателей в будущем, и эти люди могут не знать причин вашего предложения кода. – gunr2171 16 December 2014 в 23:33
  • 2
    Я с @ gunr2171 здесь. Я думаю, что читатели этого сообщения должны не только копировать-вставлять свой код, но и понимать логику алгоритма за ним :) – Liran Friedman 29 December 2015 в 08:08
  • 3
    Что такое Fill в used.Fill(false);? – Jack Griffin 7 August 2018 в 11:00

Относительно ответа Pengyang: Вот моя общая функция, которая может вернуть все комбинации из списка T:

static IEnumerable<IEnumerable<T>>
    GetCombinations<T>(IEnumerable<T> list, int length)
{
    if (length == 1) return list.Select(t => new T[] { t });

    return GetCombinations(list, length - 1)
        .SelectMany(t => list, (t1, t2) => t1.Concat(new T[] { t2 }));
}

Пример 1: n = 3, k = 2

IEnumerable<IEnumerable<int>> result =
    GetCombinations(Enumerable.Range(1, 3), 2);

Вывод - список целых списков:

{1, 1} {1, 2} {1, 3} {2, 1} {2, 2} {2, 3} {3, 1} {3, 2} {3, 3}

........................... ..................................................

Я выполнил этот пример, и я не совсем уверен в правильности результатов.

Пример 2: n = 3, k = 3

IEnumerable<IEnumerable<int>> result =
    GetCombinations(Enumerable.Range(1, 3), 3);

Вывод - список целых списков:

{1, 1, 1} {1, 1, 2} {1, 1, 3} 
{1, 2, 1} {1, 2, 2} {1, 2, 3} 
{1, 3, 1} {1, 3, 2} {1, 3, 3}
{2, 1, 1} {2, 1, 2} {2, 1, 3} 
{2, 2, 1} {2, 2, 2} {2, 2, 3} 
{2, 3, 1} {2, 3, 2} {2, 3, 3}
{3, 1, 1} {3, 1, 2} {3, 1, 3} 
{3, 2, 1} {3, 2, 2} {3, 2, 3} 
{3, 3, 1} {3, 3, 2} {3, 3, 3}

Это не должно происходить с комбинациями, иначе оно должно указывать, что оно повторяется. См. Статью http://en.wikipedia.org/ вики / Комбинация

4
ответ дан abel406 18 August 2018 в 12:55
поделиться
  • 1
    Спасибо за ваш вклад. Я обновил свой ответ с большим количеством решений. – Pengyang 13 March 2014 в 09:11

Подробный ответ см .: Дональд Кнут, «Искусство компьютерного программирования» (ака TAOCP). Том 4А, «Перечисление и обратное отслеживание», глава 7.2. Создание всех возможностей. http://www-cs-faculty.stanford.edu/~uno/taocp.html

1
ответ дан danatel 18 August 2018 в 12:55
поделиться

Возможно, kwcombinatorics может оказать некоторую помощь (см. пример на домашней странице):

Библиотека KwCombinatorics - это 3 класса, которые предоставляют 3 разных способа создания упорядоченных (ранжированных ) списки комбинаций чисел. Эти комбинаторики полезны для тестирования программного обеспечения, что позволяет генерировать различные типы возможных комбинаций ввода. Другие виды использования включают решение математических задач и азартных игр.

2
ответ дан gimel 18 August 2018 в 12:55
поделиться

Это называется перестановками.

Это может дать вам перестановки любой коллекции:

public class Permutation {

  public static IEnumerable<T[]> GetPermutations<T>(T[] items) {
    int[] work = new int[items.Length];
    for (int i = 0; i < work.Length; i++) {
      work[i] = i;
    }
    foreach (int[] index in GetIntPermutations(work, 0, work.Length)) {
      T[] result = new T[index.Length];
      for (int i = 0; i < index.Length; i++) result[i] = items[index[i]];
      yield return result;
    }
  }

  public static IEnumerable<int[]> GetIntPermutations(int[] index, int offset, int len) {
    if (len == 1) {
      yield return index;
    } else if (len == 2) {
      yield return index;
      Swap(index, offset, offset + 1);
      yield return index;
      Swap(index, offset, offset + 1);
    } else {
      foreach (int[] result in GetIntPermutations(index, offset + 1, len - 1)) {
        yield return result;
      }
      for (int i = 1; i < len; i++) {
        Swap(index, offset, offset + i);
        foreach (int[] result in GetIntPermutations(index, offset + 1, len - 1)) {
          yield return result;
        }
        Swap(index, offset, offset + i);
      }
    }
  }

  private static void Swap(int[] index, int offset1, int offset2) {
    int temp = index[offset1];
    index[offset1] = index[offset2];
    index[offset2] = temp;
  }

}

Пример:

string[] items = { "one", "two", "three" };
foreach (string[] permutation in Permutation.GetPermutations<string>(items)) {
  Console.WriteLine(String.Join(", ", permutation));
}
14
ответ дан Guffa 18 August 2018 в 12:55
поделиться
  • 1
    Я думаю, что есть разница между перестановкой и комбинацией – Ahmed Said 23 December 2009 в 12:59
  • 2
    @Ahmed: «Все различные способы упорядочивания элементов». явно перестановки. Если ваш код делает что-то другое, тогда он не отвечает на вопрос. – Guffa 23 December 2009 в 13:07
  • 3
    Как я могу использовать вышеприведенный класс для этого типа коллекции float [,] permutations = new float [90,600]; Было бы очень полезно, если бы вы могли объяснить пример. – Alex David 19 February 2013 в 08:55
  • 4
    @RAZER: вам придется сгладить его до одного массива измерений, однако количество перестановок будет многословным. Я даже не могу его рассчитать. Всего 3000 предметов дали бы 4.15e + 9130 перестановки ... – Guffa 19 February 2013 в 09:02
  • 5
    Извините, что объявление похоже на этот список & lt; int [] & gt; image_matrix = new List & lt; int [] & gt; (); Поэтому я думаю, что только 90 перестановок. – Alex David 19 February 2013 в 09:41

Другая версия решения, предоставленного Gufa. Ниже полный исходный код класса:

using System.Collections.Generic;

namespace ConsoleApplication1
{
    public class Permutation
    {

        public IEnumerable<T[]> GetPermutations<T>(T[] items)
        {
            var work = new int[items.Length];
            for (var i = 0; i < work.Length; i++)
            {
                work[i] = i;
            }
            foreach (var index in GetIntPermutations(work, 0, work.Length))
            {
                var result = new T[index.Length];
                for (var i = 0; i < index.Length; i++) result[i] = items[index[i]];
                yield return result;
            }
        }

        public IEnumerable<int[]> GetIntPermutations(int[] index, int offset, int len)
        {
            switch (len)
            {
                case 1:
                    yield return index;
                    break;
                case 2:
                    yield return index;
                    Swap(index, offset, offset + 1);
                    yield return index;
                    Swap(index, offset, offset + 1);
                    break;
                default:
                    foreach (var result in GetIntPermutations(index, offset + 1, len - 1))
                    {
                        yield return result;
                    }
                    for (var i = 1; i < len; i++)
                    {
                        Swap(index, offset, offset + i);
                        foreach (var result in GetIntPermutations(index, offset + 1, len - 1))
                        {
                            yield return result;
                        }
                        Swap(index, offset, offset + i);
                    }
                    break;
            }
        }

        private static void Swap(IList<int> index, int offset1, int offset2)
        {
            var temp = index[offset1];
            index[offset1] = index[offset2];
            index[offset2] = temp;
        }

    }
}

Это действительно работало так, как должно для комбинаций. Но это не позволяет выбирать комбинации n в k ...

1
ответ дан Jeffrey Kevin Pry 18 August 2018 в 12:55
поделиться
  • 1
    Спасибо Джеффри Кевину Пра за исправления. – abel406 17 July 2018 в 13:58

Есть пары очень простого способа найти комбинацию ввода строки пользователем.

Первый способ с помощью LINQ

private static IEnumerable<string> FindPermutations(string set)
        {
            var output = new List<string>();
            switch (set.Length)
            {
                case 1:
                    output.Add(set);
                    break;
                default:
                    output.AddRange(from c in set let tail = set.Remove(set.IndexOf(c), 1) from tailPerms in FindPermutations(tail) select c + tailPerms);
                    break;
            }
            return output;
        }

Используйте эту функцию, например

Console.WriteLine("Enter a sting ");

            var input = Console.ReadLine();

            foreach (var stringCombination in FindPermutations(input))
            {
                Console.WriteLine(stringCombination);
            }
            Console.ReadLine();

Другим способом является использование цикла

// 1. remove first char 
    // 2. find permutations of the rest of chars
    // 3. Attach the first char to each of those permutations.
    //     3.1  for each permutation, move firstChar in all indexes to produce even more permutations.
    // 4. Return list of possible permutations.
    public static string[] FindPermutationsSet(string word)
    {
        if (word.Length == 2)
        {
            var c = word.ToCharArray();
            var s = new string(new char[] { c[1], c[0] });
            return new string[]
            {
                word,
                s
            };
        }
        var result = new List<string>();
        var subsetPermutations = (string[])FindPermutationsSet(word.Substring(1));
        var firstChar = word[0];
        foreach (var temp in subsetPermutations.Select(s => firstChar.ToString() + s).Where(temp => temp != null).Where(temp => temp != null))
        {
            result.Add(temp);
            var chars = temp.ToCharArray();
            for (var i = 0; i < temp.Length - 1; i++)
            {
                var t = chars[i];
                chars[i] = chars[i + 1];
                chars[i + 1] = t;
                var s2 = new string(chars);
                result.Add(s2);
            }
        }
        return result.ToArray();
    }

, вы можете использовать это как

Console.WriteLine("Enter a sting ");

        var input = Console.ReadLine();

        Console.WriteLine("Here is all the possable combination ");
        foreach (var stringCombination in FindPermutationsSet(input))
        {
            Console.WriteLine(stringCombination);
        }
        Console.ReadLine();
2
ответ дан MANISH KUMAR CHOUDHARY 18 August 2018 в 12:55
поделиться

UPDATED

Вот набор общих функций (требуется .net 3.5 или выше) для разных сценариев. Выходы предназначены для списка {1, 2, 3, 4} и длины 2.

Перестановки с повторением

static IEnumerable<IEnumerable<T>> 
    GetPermutationsWithRept<T>(IEnumerable<T> list, int length)
{
    if (length == 1) return list.Select(t => new T[] { t });
    return GetPermutationsWithRept(list, length - 1)
        .SelectMany(t => list, 
            (t1, t2) => t1.Concat(new T[] { t2 }));
}

Выход:

{1,1} {1,2} {1,3} {1,4} {2,1} {2,2} {2,3} {2,4} {3,1} {3,2} {3,3} {3,4} {4,1} {4,2} {4,3} {4,4}

Перестановки

static IEnumerable<IEnumerable<T>>
    GetPermutations<T>(IEnumerable<T> list, int length)
{
    if (length == 1) return list.Select(t => new T[] { t });
    return GetPermutations(list, length - 1)
        .SelectMany(t => list.Where(o => !t.Contains(o)),
            (t1, t2) => t1.Concat(new T[] { t2 }));
}

Выход:

{1,2} {1,3} {1,4} {2,1} {2,3} {2,4} {3,1} {3,2} {3,4} {4,1} {4,2} {4,3}

K-комбинации с повторением

static IEnumerable<IEnumerable<T>> 
    GetKCombsWithRept<T>(IEnumerable<T> list, int length) where T : IComparable
{
    if (length == 1) return list.Select(t => new T[] { t });
    return GetKCombsWithRept(list, length - 1)
        .SelectMany(t => list.Where(o => o.CompareTo(t.Last()) >= 0), 
            (t1, t2) => t1.Concat(new T[] { t2 }));
}

Выход:

{1,1} {1,2} {1,3} {1,4} {2,2} {2,3} {2,4} {3,3} {3,4} {4,4}

K-комбинации

static IEnumerable<IEnumerable<T>> 
    GetKCombs<T>(IEnumerable<T> list, int length) where T : IComparable
{
    if (length == 1) return list.Select(t => new T[] { t });
    return GetKCombs(list, length - 1)
        .SelectMany(t => list.Where(o => o.CompareTo(t.Last()) > 0), 
            (t1, t2) => t1.Concat(new T[] { t2 }));
}

Выход:

{1,2} {1,3} {1,4} {2,3} {2,4} {3,4}
69
ответ дан Pengyang 18 August 2018 в 12:55
поделиться
  • 1
    хороший подход, но он не работает с GetKCombs( new int[] { 1, 2, 3 }, 3); – fubo 12 November 2015 в 14:36
  • 2
    Перестановки не выполняются, если параметр IEnumerable содержит одну и ту же строку 2 раза. – Davidm176 29 August 2017 в 09:27
  • 3
    K-комбинации терпят неудачу со строками, по-видимому, проблема с CompareTo () : source = { aa, bb, cc }, length = 2 : { aa bb }, { aa cc }, { bb cc }´ [correct] source = {big, red, car}, length = 2: {big red}, {big car}, { car red} '- & gt; [неверно: должно быть: {красный автомобиль}] – Jack Griffin 7 August 2018 в 10:31

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

private static void CombinationsOfItemsInAnArray()    
{
        int[] arr = { 10, 50, 3, 1, 2 }; //unique elements

        var numberSet = new HashSet<int>();
        var combinationList = new List<Tuple<int, int>>();
        foreach (var number in arr)
        {
            if (!numberSet.Contains(number))
            {
                //create all tuple combinations for the current number against all the existing number in the number set
                foreach (var item in numberSet)
                    combinationList.Add(new Tuple<int, int>(number, item));

                numberSet.Add(number);
            }
        }

        foreach (var item in combinationList)
        {
            Console.WriteLine("{{{0}}} - {{{1}}}",item.Item1,item.Item2);
        }
    }

Когда я вызываю этот метод в консольном приложении, я становлюсь ниже вывода:

{50} - {10}
{3} - {10}
{3} - {50}
{1} - {10}
{1} - {50}
{1} - {3}
{2} - {10}
{2} - {50}
{2} - {3}
{2} - {1}
0
ответ дан RBT 18 August 2018 в 12:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: