Алгоритм комбинирования: выведите все возможные комбинации R
Что такое комбинация?
Комбинация – это своего рода расположение некоторых данных объектов. Говоря математическим языком, Комбинация — это набор вариантов/выбор предметов из уникального набора предметов/объектов. Здесь порядок элементов не имеет значения. Он также известен как метод расчета общего результата события, при котором порядок результата не имеет значения.
Например, вам дали сумку пяти разных цветов и попросили создать узор из любых трех цветов. Вы также можете выбрать любые 5 цвета из 3, а затем расположить их в разном порядке.
Предположим, что это цвета RGYBI (R = красный, G = зеленый, Y = желтый, B = синий, I = индиго). Итак, возможный шаблон может быть RGB, RGY и т. д.
Давайте посмотрим на следующий рисунок:

Объяснение:
- Возьмите любые 4 цвета из 5 и перечислите их.
- Из каждого блока из 4 цветов выберите любые 3 и перечислите их все. Например, на рисунке мы выбрали только «RGBI» и показали 4 комбинации.
- За этим стоит теория, позволяющая подсчитать общее количество комбинаций, которые мы можем составить. Комбинацию r элементов из n можно математически представить как:
Знак «!» означает факториал, Например,
Н! = Н * (Н-1) * (Н-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) Сортируем входной массив данных по возрастанию. Временная сложность сортировки составляет О(п*лог(п)).
Шаг 2) Создайте еще один массив, содержащий уникальный элемент из данных временного массива.
Шаг 3) Затем выполните функцию комбинирования.
Таким образом, общая временная сложность становится = На2) + O(nLog(n)). Мы можем считать это O(n2), как n2 намного больше, чем n*log(n).
Метод-1: фиксированный элемент с рекурсией
В этом методе мы выбираем элемент, а затем находим комбинацию элементов r-1. Когда мы выбираем элемент из остальной части элемента, мы делаем это рекурсивно, и поэтому это называется фиксированным элементом и рекурсией.
Продемонстрируем алгоритм пошагово на схеме:
Шаги приведены ниже:
Шаг 1) В первом слое возьмите n-r+1 элементов. То есть мы взяли 3 элемента.
Шаг 2) Выберите элемент второго слоя и поднимите его до номера. Итак, если мы возьмем «R», то вместе с R мы сможем взять G, Y и B.
Шаг 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)
Итак, для рекурсивного алгоритма будет две рекурсивные логики для поиска комбинации из r элементов из заданного массива размера n.
- Элемент включен в текущую Комбинацию
- Элемент исключен из текущей комбинации
Псевдокод
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). Итак, если вы используете словарь, то общая временная сложность выполнения кода будет:
О(1) + О(п*п)
Эквивалент O(n*n).
Используя предыдущий метод для отслеживания дубликатов, нам нужно O(n*log(n)) для сортировки; для сравнения нам нужно O(n), а сама функция занимает O(n*n). Общая временная сложность будет:
O(n*log(n)) + O(n) +O(n*n)