Алгоритм поєднання: Вивести всі можливі комбінації R

Що таке комбінація?

Комбінація - це своєрідне розташування деяких заданих об'єктів. З математичної точки зору, Комбінація – це набір варіантів/вибору предметів з унікального набору предметів/об’єктів. Тут порядок елементів не має значення. Він також відомий як метод обчислення загального результату події, де порядок результатів не має значення.

Наприклад, вам дали сумку 5 різних кольорів і попросили створити візерунок із будь-яких 3 кольорів. Ви також можете вибрати будь-які 3 кольори з 4, а потім розташувати їх у різному порядку.

Припустімо, що кольори RGYBI(R= червоний, G= зелений, Y= жовтий, B= синій, I= індиго). Отже, можливий шаблон може бути RGB, RGY тощо.

Давайте подивимося на наступний малюнок:

Поєднання кольорів
Поєднання кольорів

Пояснення:

  • Візьміть будь-які 4 кольори з 5 і перелічіть їх
  • З кожного блоку з 4 кольорами виберіть будь-які 3 і перерахуйте їх усі. Наприклад, ми вибрали лише «RGBI» на малюнку та показали 4 комбінації.
  • За цим стоїть теорія, яка обчислює загальну кількість комбінацій, які ми можемо створити. Комбінацію r елементів із n можна математично представити як:
Формула поєднання

Формула поєднання

Знак "!" означає Факторіал, Наприклад,
N! = N * (N-1) * (N-2) * … * 3 * 2 * 1
Скажи, 5! = 5*4*3*2*1 = 120

Отже, для нашої вищезазначеної задачі ми маємо 5 кольорів, що означає n = 5, і в будь-який момент часу нам потрібно вибрати будь-які 3. Отже, r = 3. Після обчислення ми отримуємо,

Комбінація

Для вищевказаного сценарію можливе всього 10 комбінацій кольорів.

Аналіз часової складності для Комбінації

Тепер, скажімо, задано масив розміром n, нас просять взяти r елементів із масиву та виконати комбінації r елементів.

Якщо задано масив розміром n, він займе O(n2) час на виконання завдання. Крім того, якщо ми хочемо видалити повторюваний запис, тоді,

Нам потрібно виконати наступні дії:

Крок 1) Відсортувати дані вхідного масиву за зростанням. Часова складність сортування O(n*log(n)).

Крок 2) Створіть ще один масив, що містить унікальний елемент із заданих даних тимчасового масиву.

Крок 3) Потім виконайте функцію комбінування.

Отже, загальна часова складність стає = О (н.)2) + O(nLog(n)). Ми можемо вважати це O(n2), як п2 набагато більше, ніж n*log(n).

Метод 1: фіксований елемент із рекурсією

У цьому методі ми виберемо елемент, а потім знайдемо комбінацію елементів r-1. Оскільки ми вибираємо елемент із решти елемента, ми робимо рекурсивно, і тому це називається фіксованим елементом і рекурсією.

Продемонструємо крок за кроком алгоритм за допомогою схеми:

Фіксований елемент із рекурсією

Кроки наведені нижче:

Крок 1) У першому шарі візьміть n-r+1 елементів. Тобто ми взяли 3 елементи.

Крок 2) Виберіть елемент із 2-го шару та перенесіть його до nr. Отже, якщо ми візьмемо «R», то з R ми можемо взяти G, Y і B.

Крок 3) Виберіть елемент із 3-го шару та піднесіть його до n-го елемента та сформуйте блоки, що містять 3 елементи кожен.

Цифра вище є значенням, що повертається рекурсією. Буде надруковано лише останній шар.

Псевдокодекс

function combination:
pass in: inputArray, combinationArray, start, end, index, r
if index is equal to r:
for each element in combinationArray:
print each element
return
for i = start:
if i <=end and end -i+1 > r-index:
combinationArray[index] = inputArray[i]
call combination function again with updated parameter

Реалізація на C/C++

#include<bits/stdc++.h>
#include<stdio.h>
void Combination(char inputArray[], char combinationArray[], int start, int end, int index, int r) {
  if (index == r) {
    for (int i = 0; i & lt; r; i++) {
      printf("%c", combinationArray[i]);
    }
    printf("\n");
    return;
  }
  for (int i = start; i & lt; = end & amp; & amp; end - i + 1 & gt; = r - index; i++) {
    combinationArray[index] = inputArray[i];
    Combination(inputArray, combinationArray, i + 1, end, index + 1, r);
  }
}
int main() {
  char inputArray[] = {'R','G','Y','B','I'};
  int n = sizeof(inputArray) / sizeof(inputArray[0]);
  int r = 3;
  char combinationArray[r];
  printf("Combinations:\n");
  Combination(inputArray, combinationArray, 0, n - 1, 0, r);
}

вихід:

Combinations:
RGY
RGB
RGI
RYB
RYI
RBI
GYB
GYI
GBI
YBI

Реалізація в Python

def Combination(inputArray, combinationArray, start, end, index, r):
    if index == r:
    for item in combinationArray:
    print(item, end = " ")
print()
return
i = start
while (i & lt; = end and end - i + 1 & gt; = r - index):
    combinationArray[index] = inputArray[i]
Combination(inputArray, combinationArray, i + 1, end, index + 1, r)
i += 1
inputArray = "RGYBI"
n = len(inputArray)
r = 3
combinationArray = [0] * r
Combination(inputArray, combinationArray, 0, n - 1, 0, r)

вихід:

R G Y 
R G B
R G I
R Y B
R Y I
R B I
G Y B
G Y I
G B I
Y B I

Спосіб 2 (включити та виключити кожен елемент)

Цей метод заснований на тотожності Паскаля. Раніше ми використовували рекурсію для обчислення nCr. Тут метод просто розділений замість складного циклу.

Відповідно до особистості Паскаля,

nCr = (n-1)Cr + (n-1)C(r-1)

Отже, буде 2 рекурсивні логіки для рекурсивного алгоритму, щоб знайти комбінацію r елементів із заданого масиву розміром n.

  1. Елемент включено в поточну комбінацію
  2. Елемент виключено з поточної комбінації

Псевдокодекс

function combination:
pass in: inputArray, combinationArray, n, r, index, i
if the index is equal to r:
for each element in combination array:
print each element
if i>=n:
return
  combinationArray[index] = inputArray[i]
  combination(inputArray, combinationArray, n, r, index+1, i+1)
  combination(inputArray, combinationArray, n, r, index, i+1)

Реалізація на C/C++

#include<bits/stdc++.h>
#include<stdio.h>
void Combination(char inputArray[], char combinationArray[], int n, int r, int index, int i) {
  if (index == r) {
    for (int j = 0; j & lt; r; j++) {
      printf("%c", combinationArray[j]);
    }
    printf("\n");
    return;
  }
  if (i & gt; = n)
    return;
  combinationArray[index] = inputArray[i];
  Combination(inputArray, combinationArray, n, r, index + 1, i + 1);
  Combination(inputArray, combinationArray, n, r, index, i + 1);
}
int main() {
  char inputArray[] = {'R','G','Y','B','I'};
  int n = sizeof(inputArray) / sizeof(inputArray[0]);
  int r = 3;
  char combinationArray[r];
  printf("Combinations:\n");
  Combination(inputArray, combinationArray, n, r, 0, 0);
}

вихід:

Combinations:
RGY
RGB
RGI
RYB
RYI
RBI
GYB
GYI
GBI
YBI

Реалізація в Python

def Combination(inputArray, combinationArray, n, r, index, i):
    if index == r:
    for item in combinationArray:
    print(item, end = " ")
print()
return
if i & gt; = n:
    return
combinationArray[index] = inputArray[i]
Combination(inputArray, combinationArray, n, r, index + 1, i + 1);
Combination(inputArray, combinationArray, n, r, index, i + 1);
inputArray = "RGYBI"
n = len(inputArray)
r = 3
combinationArray = [""] * r
Combination(inputArray, combinationArray, n, r, 0, 0)

вихід:

R G Y
R G B
R G I
R Y B
R Y I
R B I
G Y B
G Y I
G B I
Y B I

Обробка повторюваних комбінацій

Іноді у вхідному масиві можуть бути повторювані елементи.

Наприклад,

  • Вхідний масив містить n = {5, 2, 3, 1, 5}.
  • Тут ми бачимо, що 5 присутнє 2 рази.
  • Тепер, якщо ми хочемо запустити код для цього масиву, деякі комбінації будуть повторені.
  • Ми знайдемо {5, 2, 5}, {5, 2, 3} тощо або будь-яку комбінацію, яка містить 5, буде повторено.

Ми можемо використовувати ці два методи:

  • Відсортуйте вхідний масив. Сортування займе O(nlog(n)) часу.
  • Потім збільште значення i, тоді як значення i та i+1 однакові. По суті, помістіть наступні два рядки коду у функцію Combination.
// For c/c++
while(inputArray[i] == inputArray[i+1]){
  i++;
}
# for python
  while inputArray[i]==inputArray[i+1]:
    i+=1

Використання словника або невпорядкованої карти для відстеження повторюваних комбінацій

Отже, якщо ми не хочемо сортувати елементи для відстеження дубліката, ми можемо виконати наведені кроки.

Крок 1) Оголосити глобальний словник або хеш-карту.
Крок 2) Перемістіть згенеровану комбінацію на хеш-карту та збільште значення на одиницю. Комбінація є ключем, а їх виникнення є значеннями.
Крок 3) коли функція завершить роботу, ми просто надрукуємо всі ключі з хеш-карти або словника.

Ось реалізація на python

unique_combination = dict()
def Combination(inputArray, combinationArray, n, r, index, i):
    if index == r:
    temp_combination = ""
for item in combinationArray:
    temp_combination += item
unique_combination[temp_combination] = unique_combination.get(temp_combination, 0) + 1
return
if i & gt; = n:
    return
combinationArray[index] = inputArray[i]
Combination(inputArray, combinationArray, n, r, index + 1, i + 1);
Combination(inputArray, combinationArray, n, r, index, i + 1);
inputArray = "RGYBIB"
n = len(inputArray)
r = 3
combinationArray = [""] * r
Combination(inputArray, combinationArray, n, r, 0, 0)
for item in unique_combination.keys():
    print(item)

вихід:

RGY
RGB
RGI
RYB
RYI
RBI
RBB
RIB
GYB
GYI
GBI
GBB
GIB
YBI
YBB
YIB
BIB

Тут ви бачите, що введено «RGYBIB». Як правило, має бути кілька повторюваних комбінацій. Але оскільки ми використовували словник і розглядали кожну комбінацію як ключ, ми можемо надрукувати лише унікальну комбінацію.

Тепер, якщо ви напишете «print(unique_combination)», ви побачите частоту кожної комбінації. Це буде показано так:

{'RGY': 1, 'RGB': 2, 'RGI': 1, 'RYB': 2, 'RYI': 1, 'RBI': 1, 'RBB': 1, 'RIB': 1, 'GYB': 2, 'GYI': 1, 'GBI': 1, 'GBB': 1, 'GIB': 1, 'YBI': 1, 'YBB': 1, 'YIB': 1, 'BIB': 1}

Отже, ми бачимо, що RGB, RYB, GYB відбулися 2 рази. Часова складність вставки ключа до словника в основному становить O(1). Отже, якщо ви використовуєте словник, то загальна складність часу для виконання коду буде:

O(1) + O(n*n)

Еквівалент O(n*n).

Використовуючи попередній метод для відстеження дублікатів, нам потрібно O(n*log(n)) для сортування; для порівняння нам потрібно O(n), а сама функція приймає O(n*n). Загальна трудомісткість становитиме:

O(n*log(n)) + O(n) +O(n*n)