Chcę napisać funkcję, która pobiera tablicę liter jako argument i liczbę tych liter do wyboru.
Załóżmy, że podajesz tablicę 8 liter i chcesz z tego wybrać 3 litery. Następnie powinieneś otrzymać:
8! / ((8 - 3)! * 3!) = 56
W zamian tablice (lub słowa) składające się z 3 liter każda.
algorithm
combinations
ique
źródło
źródło
Odpowiedzi:
Art of Computer Programming Volume 4: Fascicle 3 ma mnóstwo takich, które mogą lepiej pasować do twojej konkretnej sytuacji niż to, co opisuję.
Szare Kody
Problem, z którym się zetkniesz, to oczywiście pamięć i dość szybko będziesz miał problemy z 20 elementami w zestawie - 20 C 3 = 1140. A jeśli chcesz iterować po zestawie, najlepiej użyć zmodyfikowanego szarego algorytm kodu, więc nie trzymasz ich wszystkich w pamięci. Generują one następną kombinację z poprzednich i unikają powtórzeń. Istnieje wiele z nich do różnych zastosowań. Czy chcemy zmaksymalizować różnice między kolejnymi kombinacjami? zminimalizować? i tak dalej.
Niektóre z oryginalnych artykułów opisujących szare kody:
Oto kilka innych artykułów na ten temat:
Chase's Twiddle (algorytm)
Phillip J Chase, ` Algorytm 382: Kombinacje M z N obiektów (1970)
Algorytm w C ...
Indeks kombinacji w porządku leksykograficznym (algorytm klamry 515)
Możesz także odwoływać się do kombinacji według jej indeksu (w porządku leksykograficznym). Zdając sobie sprawę, że indeks powinien być pewną zmianą od prawej do lewej w oparciu o indeks, możemy skonstruować coś, co powinno odzyskać kombinację.
Mamy więc zestaw {1,2,3,4,5,6} ... i chcemy trzech elementów. Powiedzmy, że {1,2,3} możemy powiedzieć, że różnica między elementami jest jedna, w kolejności i minimalna. {1,2,4} ma jedną zmianę i jest leksykograficznie liczbą 2. Zatem liczba „zmian” na ostatnim miejscu odpowiada jednej zmianie w porządku leksykograficznym. Drugie miejsce, z jedną zmianą {1,3,4}, ma jedną zmianę, ale uwzględnia więcej zmian, ponieważ jest na drugim miejscu (proporcjonalnie do liczby elementów w oryginalnym zestawie).
Metoda, którą opisałem, jest, jak się wydaje, dekonstrukcją od zestawu do indeksu, musimy zrobić odwrotnie - co jest znacznie trudniejsze. W ten sposób Buckles rozwiązuje problem. Napisałem trochę C, aby je obliczyć , z niewielkimi zmianami - użyłem indeksu zbiorów, a nie zakresu liczb, aby przedstawić zbiór, więc zawsze pracujemy od 0 ... n. Uwaga:
Indeks kombinacji w porządku leksykograficznym (McCaffrey)
Jest inny sposób : jego koncepcja jest łatwiejsza do uchwycenia i zaprogramowania, ale bez optymalizacji Buckles. Na szczęście nie tworzy również duplikatów:
Zestaw, który maksymalizuje , gdzie .
Na przykład:
27 = C(6,4) + C(5,3) + C(2,2) + C(1,1)
. Tak więc 27. kombinacja leksykograficzna czterech rzeczy to: {1,2,5,6}, są to indeksy dowolnego zestawu, na który chcesz spojrzeć. Przykład poniżej (OCaml), wymagachoose
funkcji, pozostawionej czytelnikowi:Mały i prosty iterator kombinacji
Do celów dydaktycznych podano następujące dwa algorytmy. Implementują iterator i (bardziej ogólne) ogólne kombinacje folderów. Są tak szybkie, jak to możliwe, o złożoności O ( n C k ). Zużycie pamięci jest ograniczone przez
k
.Zaczniemy od iteratora, który wywoła funkcję podaną przez użytkownika dla każdej kombinacji
Bardziej ogólna wersja wywoła funkcję podaną przez użytkownika wraz ze zmienną stanu, zaczynając od stanu początkowego. Ponieważ musimy przekazać stan między różnymi stanami, nie będziemy używać pętli for, ale zamiast tego będziemy używać rekurencji,
źródło
W C #:
Stosowanie:
Wynik:
źródło
var result = new[] { 1, 2, 3, 4, 5 }.Combinations(3);
Krótkie rozwiązanie Java:
Wynik będzie
źródło
Czy mogę przedstawić moje rekurencyjne rozwiązanie tego problemu w języku Python?
Przykładowe użycie:
Podoba mi się ze względu na prostotę.
źródło
len(tuple(itertools.combinations('abcdefgh',3)))
osiągnie to samo w Pythonie przy mniejszym kodzie.for i in xrange(len(elements) - length + 1):
? W pythonie nie ma znaczenia, ponieważ wychodzenie z indeksu wycinków jest obsługiwane z wdziękiem, ale jest to prawidłowy algorytm.Powiedzmy, że twoja tablica liter wygląda następująco: „ABCDEFGH”. Masz trzy wskaźniki (i, j, k) wskazujące, których liter zamierzasz użyć dla bieżącego słowa, zaczynasz od:
Najpierw różnicujesz k, więc następny krok wygląda następująco:
Jeśli osiągnąłeś koniec, idź dalej i zmieniaj j, a następnie k ponownie.
Gdy j osiągniesz G, zaczynasz także zmieniać i.
Zapisane w kodzie wygląda to mniej więcej tak
źródło
Poniższy algorytm rekurencyjny wybiera wszystkie kombinacje elementów k z uporządkowanego zestawu:
i
swojej kombinacjii
z każdą kombinacjąk-1
elementów wybranych rekurencyjnie z zestawu elementów większych niżi
.Iteruj powyższe dla każdego
i
z zestawu.Ważne jest, aby wybrać pozostałe elementy jako większe niż
i
, aby uniknąć powtórzeń. W ten sposób [3,5] zostanie wybrany tylko raz, ponieważ [3] w połączeniu z [5], zamiast dwa razy (warunek eliminuje [5] + [3]). Bez tego warunku otrzymasz kombinacje zamiast kombinacji.źródło
W C ++ poniższa procedura wygeneruje wszystkie kombinacje odległości długości (pierwsza, k) między zakresem [pierwsza, ostatnia):
Można go użyć w następujący sposób:
Spowoduje to wydrukowanie następujących elementów:
źródło
being
ibegin
zs.begin()
, iend
zs.end()
. Kod ściśle przestrzeganext_permutation
algorytmu STL , opisanego tutaj bardziej szczegółowo.Uznałem ten wątek za przydatny i pomyślałem, że dodam rozwiązanie JavaScript, które można włamać do Firebug. W zależności od silnika JS, jeśli ciąg początkowy jest duży, może to zająć trochę czasu.
Dane wyjściowe powinny wyglądać następująco:
źródło
źródło
Krótki przykład w Pythonie:
W celu wyjaśnienia metodę rekurencyjną opisano w następującym przykładzie:
Przykład: ABCDE
Wszystkie kombinacje 3 byłyby następujące:
źródło
Prosty algorytm rekurencyjny w Haskell
Najpierw definiujemy przypadek szczególny, tj. Wybierając elementy zerowe. Daje pojedynczy wynik, którym jest pusta lista (tj. Lista zawierająca pustą listę).
Dla n> 0
x
przechodzi przez każdy element listy ixs
następuje po nim każdy elementx
.rest
wybieran - 1
elementy zxs
wywołania rekurencyjnego docombinations
. Końcowym wynikiem funkcji jest lista, w której każdy element jestx : rest
(tj. Lista, która max
głowę irest
ogon) dla każdej innej wartościx
irest
.I oczywiście, ponieważ Haskell jest leniwy, lista jest stopniowo generowana w razie potrzeby, więc możesz częściowo ocenić wykładniczo duże kombinacje.
źródło
I oto nadchodzi dziadek COBOL, bardzo złośliwy język.
Załóżmy tablicę 34 elementów po 8 bajtów każdy (czysto arbitralny wybór). Chodzi o wyliczenie wszystkich możliwych kombinacji 4-elementowych i załadowanie ich do tablicy.
Używamy 4 wskaźników, po jednym dla każdej pozycji w grupie 4
Tablica jest przetwarzana w następujący sposób:
Zmieniamy idx4 od 4 do końca. Dla każdego idx4 otrzymujemy unikalną kombinację czterech grup. Kiedy idx4 dojdzie do końca tablicy, zwiększamy idx3 o 1 i ustawiamy idx4 na idx3 + 1. Następnie uruchamiamy idx4 do końca. Postępujemy w ten sposób, zwiększając odpowiednio idx3, idx2 i idx1, aż pozycja idx1 będzie mniejsza niż 4 od końca tablicy. To kończy algorytm.
Pierwsze iteracje:
Przykład COBOL:
źródło
Oto elegancka, ogólna implementacja w Scali, jak opisano w 99 Problemach Scali .
źródło
Jeśli możesz użyć składni SQL - powiedzmy, jeśli używasz LINQ, aby uzyskać dostęp do pól struktury lub tablicy, lub bezpośrednio uzyskujesz dostęp do bazy danych, która ma tabelę o nazwie „Alfabet” za pomocą tylko jednego pola znakowego „Litera”, możesz dostosować następujące kod:
Spowoduje to zwrócenie wszystkich kombinacji 3 liter, niezależnie od liczby liter zawartych w tabeli „Alfabet” (może to być 3, 8, 10, 27 itd.).
Jeśli chcesz wszystkich permutacji, a nie kombinacji (tzn. Chcesz, aby „ACB” i „ABC” liczyły się jako różne, zamiast pojawiać się tylko raz), po prostu usuń ostatni wiersz (AND) i gotowe.
Po edycji: po ponownym przeczytaniu pytania zdaję sobie sprawę, że potrzebny jest ogólny algorytm, a nie tylko konkretny w przypadku wyboru 3 elementów. Odpowiedź Adama Hughesa jest kompletna, niestety nie mogę (jeszcze) głosować. Ta odpowiedź jest prosta, ale działa tylko wtedy, gdy chcesz dokładnie 3 elementy.
źródło
Kolejna wersja C # z leniwą generacją wskaźników kombinacji. Ta wersja utrzymuje jedną tablicę indeksów w celu zdefiniowania odwzorowania między listą wszystkich wartości a wartościami dla bieżącej kombinacji, tj. Stale wykorzystuje dodatkową przestrzeń O (k) podczas całego środowiska wykonawczego. Kod generuje poszczególne kombinacje, w tym pierwszą, w czasie O (k) .
Kod testowy:
Wynik:
źródło
c b a
to, czego on nie zawiera.https://gist.github.com/3118596
Istnieje implementacja dla JavaScript. Posiada funkcje do pobierania kombinacji k i wszystkich kombinacji tablicy dowolnych obiektów. Przykłady:
źródło
Oto leniwa oceniana wersja tego algorytmu zakodowana w języku C #:
I część testowa:
Mam nadzieję, że ci to pomoże!
źródło
Miałem algorytm permutacji użyty do euler projektu, w python:
Gdyby
powinieneś mieć wszystkie potrzebne kombinacje bez powtórzeń, potrzebujesz?
Jest to generator, więc używasz go w coś takiego:
źródło
źródło
Wersja Clojure:
źródło
Powiedzmy, że twoja tablica liter wygląda następująco: „ABCDEFGH”. Masz trzy wskaźniki (i, j, k) wskazujące, których liter zamierzasz użyć dla bieżącego słowa, zaczynasz od:
Najpierw różnicujesz k, więc następny krok wygląda następująco:
Jeśli osiągnąłeś koniec, idź dalej i zmieniaj j, a następnie k ponownie.
Gdy j osiągniesz G, zaczynasz także zmieniać i.
Na podstawie https://stackoverflow.com/a/127898/2628125 , ale bardziej abstrakcyjne, dla dowolnego rozmiaru wskaźników.
źródło
Wszystko, co zostało powiedziane i zrobione tutaj, zawiera kod O'camla. Algorytm jest widoczny z kodu.
źródło
Oto metoda, która daje wszystkie kombinacje określonego rozmiaru z ciągu o losowej długości. Podobne do rozwiązania quinmars, ale działa dla różnych danych wejściowych i k.
Kod można zmienić, aby się zawijał, tzn. „Dab” z wejścia „abcd” wk = 3.
Dane wyjściowe dla „abcde”:
źródło
W tym celu utworzyłem rozwiązanie w SQL Server 2005 i opublikowałem je na mojej stronie internetowej: http://www.jessemclain.com/downloads/code/sql/fn_GetMChooseNCombos.sql.htm
Oto przykład pokazujący użycie:
wyniki:
źródło
Oto moja propozycja w C ++
Próbowałem nałożyć jak najmniejsze ograniczenie na typ iteratora, jak mogłem, więc to rozwiązanie zakłada tylko iterator do przodu i może być const_iterator. Powinno to działać z każdym standardowym pojemnikiem. W przypadkach, gdy argumenty nie mają sensu, wyrzuca std :: invalid_argumnent
źródło
Oto kod, który niedawno napisałem w Javie, który oblicza i zwraca wszystkie kombinacje elementów „num” z elementów „outOf”.
źródło
Zwięzłe rozwiązanie JavaScript:
źródło
Algorytm:
W C #:
Dlaczego to działa?
Występuje biject pomiędzy podzbiorami zestawu n-elementów a sekwencjami n-bitowymi.
Oznacza to, że możemy dowiedzieć się, ile jest podzbiorów, licząc sekwencje.
np. cztery elementy ustawione poniżej mogą być reprezentowane przez {0,1} X {0, 1} X {0, 1} X {0, 1} (lub 2 ^ 4) różnymi sekwencjami.
Więc - wszystko, co musimy zrobić, to policzyć od 1 do 2 ^ n, aby znaleźć wszystkie kombinacje. (Ignorujemy pusty zestaw.) Następnie przetłumacz cyfry na ich reprezentację binarną. Następnie zamień elementy zestawu na „włączone” bity.
Jeśli chcesz tylko k wyników, drukuj tylko wtedy, gdy k bitów jest „włączonych”.
(Jeśli chcesz mieć wszystkie podzbiory zamiast podzbiorów długości k, usuń część cnt / kElement).
(Aby uzyskać dowód, patrz bezpłatne oprogramowanie MIT Matematyka dla informatyki, Lehman i in., Sekcja 11.2.2. Https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-042j-mathematics- na-informatyka-jesień-2010 / odczyty / )
źródło
krótki kod python, dający pozycje indeksu
źródło
Napisałem klasę do obsługi typowych funkcji do pracy ze współczynnikiem dwumianowym, który jest rodzajem problemu, na który wpada twój problem. Wykonuje następujące zadania:
Wyprowadza wszystkie indeksy K w ładnym formacie dla dowolnego N wybierającego K do pliku. Indeksy K można zastąpić bardziej opisowymi ciągami lub literami. Ta metoda sprawia, że rozwiązanie tego typu problemu jest dość proste.
Konwertuje indeksy K na właściwy indeks pozycji w posortowanej tabeli współczynników dwumianowych. Ta technika jest znacznie szybsza niż starsze opublikowane techniki oparte na iteracji. Robi to za pomocą właściwości matematycznej właściwej Trójkątowi Pascala. Mój artykuł mówi o tym. Wierzę, że jako pierwszy odkryłem i opublikowałem tę technikę, ale mogę się mylić.
Konwertuje indeks w posortowanej tabeli współczynników dwumianowych na odpowiednie indeksy K.
Używa metody Mark Dominus do obliczenia współczynnika dwumianowego, który jest znacznie mniej podatny na przepełnienie i działa z większymi liczbami.
Klasa jest napisana w .NET C # i zapewnia sposób zarządzania obiektami związanymi z problemem (jeśli występuje) za pomocą ogólnej listy. Konstruktor tej klasy przyjmuje wartość bool o nazwie InitTable, która w przypadku wartości true utworzy ogólną listę przechowującą obiekty do zarządzania. Jeśli ta wartość jest fałszywa, nie utworzy tabeli. Nie trzeba tworzyć tabeli, aby wykonać 4 powyższe metody. Dostępne są metody dostępu do tabeli.
Istnieje powiązana klasa testowa, która pokazuje, jak korzystać z klasy i jej metod. Został gruntownie przetestowany w 2 przypadkach i nie ma znanych błędów.
Aby przeczytać o tej klasie i pobrać kod, zobacz Tablizing The Binomial Coeffieicent .
Konwersja tej klasy do C ++ nie powinna być trudna.
źródło