Co to jest elegancki sposób na znalezienie wszystkich permutacji ciągu. Np. Permutacja dla ba, będzie bai ab, ale co z dłuższym ciągiem, takim jak abcdefgh? Czy jest jakiś przykład implementacji Java?
Należy wspomnieć o założeniu. Postacie są wyjątkowe. Na przykład dla ciągu „aaaa” istnieje tylko jedna odpowiedź. Aby uzyskać bardziej ogólną odpowiedź, możesz zapisać ciągi w zestawie, aby uniknąć powielania
Afshin Moazami
1
Czy powtórzenie znaków jest dozwolone, czy też powtórzenie znaków jest niedozwolone? Czy pojedynczy ciąg może mieć wiele wystąpień tego samego znaku?
Anderson Green
2
Przeczytaj teorię (lub jeśli, podobnie jak ja, jesteś leniwy, przejdź do en.wikipedia.org/wiki/Permutation ) i zaimplementuj prawdziwy algorytm. Zasadniczo możesz wygenerować sekwencję uporządkowania elementów (fakt, że jest to ciąg znaków, nie ma znaczenia) i przechodzić przez porządki, aż wrócisz do początku. Unikaj wszystkiego, co wymaga rekurencji lub manipulacji ciągiem.
CurtainDog
Odpowiedzi:
601
publicstaticvoid permutation(String str){
permutation("", str);}privatestaticvoid permutation(String prefix,String str){int n = str.length();if(n ==0)System.out.println(prefix);else{for(int i =0; i < n; i++)
permutation(prefix + str.charAt(i), str.substring(0, i)+ str.substring(i+1, n));}}
To nie jest nauka o rakietach, wymyśliłem prawie taką samą odpowiedź. Drobne poprawki: zamiast powtarzać się do momentu n==0, możesz zatrzymać poziom wcześniej o n==1i wydrukować prefix + str.
lambshaanxy
7
„jaka jest złożoność czasu i przestrzeni?” bez jakiejś częściowej odpowiedzi buforującej dowolny algorytm, który wyprowadza permutację, jest o (n!), ponieważ zestaw wyników dla pytania o permutację jest silni dla danych wejściowych.
jeremyjjbrown
9
Elegancki, tak. Ale rozwiązanie, które konwertuje na tablicę char i zamienia w celu wygenerowania permutacji, będzie wymagało znacznie mniej kopiowania i wygeneruje znacznie mniej śmieci. Również ten algorytm nie uwzględnia powtarzających się znaków.
Gene,
20
@AfshinMoazami Myślę, że str. Podciąg (i + 1, n) można zastąpić str. Podciąg (i + 1). Użycie str.substring (i) spowoduje błąd java.lang.StackOverflowError.
Ayusman,
196
Użyj rekurencji.
Wypróbuj kolejno każdą z liter jako pierwszą, a następnie znajdź wszystkie permutacje pozostałych liter za pomocą wywołania rekurencyjnego.
Podstawowym przypadkiem jest, gdy wejście jest pustym ciągiem, jedyną permutacją jest pusty ciąg.
Jak dodać typ zwrotu do metody permute? kompilator nie może określić typu zwracanego przez tę metodę przy każdej iteracji, nawet jeśli jest to oczywiście typ String.
user1712095
Jak zapewnić różne permutacje w tej metodzie?
kapad
70
Oto moje rozwiązanie oparte na książce „Cracking the Coding Interview” (P54):
/**
* List permutations of a string.
*
* @param s the input string
* @return the list of permutations
*/publicstaticArrayList<String> permutation(String s){// The resultArrayList<String> res =newArrayList<String>();// If input string's length is 1, return {s}if(s.length()==1){
res.add(s);}elseif(s.length()>1){int lastIndex = s.length()-1;// Find out the last characterString last = s.substring(lastIndex);// Rest of the stringString rest = s.substring(0, lastIndex);// Perform permutation on the rest string and// merge with the last character
res = merge(permutation(rest), last);}return res;}/**
* @param list a result of permutation, e.g. {"ab", "ba"}
* @param c the last character
* @return a merged new list, e.g. {"cab", "acb" ... }
*/publicstaticArrayList<String> merge(ArrayList<String> list,String c){ArrayList<String> res =newArrayList<>();// Loop through all the string in the listfor(String s : list){// For each string, insert the last character to all possible positions// and add them to the new listfor(int i =0; i <= s.length();++i){String ps =newStringBuffer(s).insert(i, c).toString();
res.add(ps);}}return res;}
Strona (71) w Cracking the Coding Interview Book, wydanie 6. :)
KarimIhab
5
Czy to naprawdę dobre rozwiązanie? Polega na przechowywaniu wyników na liście, dlatego w przypadku krótkiego ciągu wejściowego wymyka się spod kontroli.
Ze wszystkich rozwiązań podanych tutaj i na innych forach najbardziej podobał mi się Mark Byers. Ten opis naprawdę zmusił mnie do myślenia i samodzielnego kodowania. Szkoda, że nie mogę głosować na jego rozwiązanie, ponieważ jestem nowicjuszem.
W każdym razie tutaj jest moja implementacja jego opisu
publicclassPermTest{publicstaticvoid main(String[] args)throwsException{String str ="abcdef";StringBuffer strBuf =newStringBuffer(str);
doPerm(strBuf,0);}privatestaticvoid doPerm(StringBuffer str,int index){if(index == str.length())System.out.println(str);else{//recursively solve this by placing all other chars at current first pos
doPerm(str, index+1);for(int i = index+1; i < str.length(); i++){//start swapping all other chars with current first char
swap(str,index, i);
doPerm(str, index+1);
swap(str,i, index);//restore back my string buffer}}}privatestaticvoid swap(StringBuffer str,int pos1,int pos2){char t1 = str.charAt(pos1);
str.setCharAt(pos1, str.charAt(pos2));
str.setCharAt(pos2, t1);}}
Wolę to rozwiązanie przed pierwszym w tym wątku, ponieważ to rozwiązanie używa StringBuffer. Nie powiedziałbym, że moje rozwiązanie nie tworzy żadnego łańcucha tymczasowego (faktycznie robi to system.out.printlntam, gdzie toString()wywoływany jest StringBuffer). Ale po prostu uważam, że jest to lepsze niż pierwsze rozwiązanie, w którym powstaje zbyt wiele literałów łańcuchowych. Może być jakimś facetem od wydajności, który może to ocenić pod względem „pamięci” (na „czas” to już opóźnia się z powodu tej dodatkowej „wymiany”)
Dlaczego nie po prostu zrobić if(index == str.length())i doPerm(str, index + 1);? currPosWydaje się tu zbędne.
Robur_131,
Przepraszam, czy możesz rozwinąć więcej pytań? Czy po prostu sugerujesz, aby nie używać dodatkowej zmiennej currPos (używanej z powodu wielu wystąpień, a także czytelności), jeśli nie, wklej rozwiązanie, które sugerujesz, aby
rzucić
Ach, rozumiem, że miałeś na myśli zmianę warunków bazowych z indeksowaniem do przodu. Działa w porządku. Tylko na to, że na przedstawione przeze mnie rozwiązanie wpłynęły głównie inne wówczas rozwiązania, które często przechodziły przez obcięty łańcuch zamiast oryginalnego (który przypadek 0 ma sens). Niemniej jednak dziękuję za wskazanie. Zobaczę, czy mogę edytować, minęły lata, odkąd zalogowałem się na tej stronie.
srikanth yaradla
22
Bardzo podstawowym rozwiązaniem w Javie jest użycie rekurencji + zestawu (aby uniknąć powtórzeń), jeśli chcesz przechowywać i zwracać ciągi rozwiązania:
publicstaticSet<String> generatePerm(String input){Set<String> set =newHashSet<String>();if(input =="")return set;Character a = input.charAt(0);if(input.length()>1){
input = input.substring(1);Set<String> permSet = generatePerm(input);for(String x : permSet){for(int i =0; i <= x.length(); i++){
set.add(x.substring(0, i)+ a + x.substring(i));}}}else{
set.add(a +"");}return set;}
@ashisahu O (n!), ponieważ mamy n! permutacje w danym ciągu o długości n.
Zok
17
Wszyscy poprzedni współpracownicy wykonali świetną robotę wyjaśniając i udostępniając kod. Pomyślałem, że powinienem również podzielić się tym podejściem, ponieważ mogłoby to komuś pomóc. Rozwiązanie oparte jest na ( algorytm hałd )
Kilka rzeczy:
Zauważ, że ostatni element przedstawiony w programie Excel służy wyłącznie do lepszej wizualizacji logiki. Tak więc rzeczywiste wartości w ostatniej kolumnie wyniosłyby 2,1,0 (gdybyśmy uruchomili kod, ponieważ mamy do czynienia z tablicami, a tablice zaczynają się od 0).
Algorytm zamiany odbywa się na podstawie parzystych lub nieparzystych wartości bieżącej pozycji. Jest to bardzo zrozumiałe, jeśli spojrzysz na to, gdzie wywoływana jest metoda zamiany. Możesz zobaczyć, co się dzieje.
Oto co się dzieje:
publicstaticvoid main(String[] args){String ourword ="abc";String[] ourArray = ourword.split("");
permute(ourArray, ourArray.length);}privatestaticvoid swap(String[] ourarray,int right,int left){String temp = ourarray[right];
ourarray[right]= ourarray[left];
ourarray[left]= temp;}publicstaticvoid permute(String[] ourArray,int currentPosition){if(currentPosition ==1){System.out.println(Arrays.toString(ourArray));}else{for(int i =0; i < currentPosition; i++){// subtract one from the last position (here is where you are// selecting the the next last item
permute(ourArray, currentPosition -1);// if it's odd positionif(currentPosition %2==1){
swap(ourArray,0, currentPosition -1);}else{
swap(ourArray, i, currentPosition -1);}}}}
publicstaticvoid permute(String s){if(null==s || s.isEmpty()){return;}// List containing words formed in each iteration List<String> strings =newLinkedList<String>();
strings.add(String.valueOf(s.charAt(0)));// add the first element to the list// Temp list that holds the set of strings for // appending the current character to all position in each word in the original listList<String> tempList =newLinkedList<String>();for(int i=1; i< s.length(); i++){for(int j=0; j<strings.size(); j++){
tempList.addAll(merge(s.charAt(i), strings.get(j)));}
strings.removeAll(strings);
strings.addAll(tempList);
tempList.removeAll(tempList);}for(int i=0; i<strings.size(); i++){System.out.println(strings.get(i));}}/**
* helper method that appends the given character at each position in the given string
* and returns a set of such modified strings
* - set removes duplicates if any(in case a character is repeated)
*/privatestaticSet<String> merge(Character c,String s){if(s==null|| s.isEmpty()){returnnull;}int len = s.length();StringBuilder sb =newStringBuilder();Set<String> list =newHashSet<String>();for(int i=0; i<= len; i++){
sb =newStringBuilder();
sb.append(s.substring(0, i)+ c + s.substring(i, len));
list.add(sb.toString());}return list;}
to rozwiązanie wydaje się błędne System.out.println(permute("AABBC").size());wyświetla 45, ale w rzeczywistości 5! = 120
Mladen Adamovic
11
Użyjmy danych wejściowych abcJako przykład .
Zacznij od ostatniego elementu ( c) w zestawie ( ["c"]), a następnie dodaj drugi ostatni element ( b) do jego przodu, końca i wszystkich możliwych pozycji na środku, tworząc go, ["bc", "cb"]a następnie w ten sam sposób doda następny element od back ( a) do każdego ciągu w zestawie, dzięki czemu:
"a"+"bc"=["abc","bac","bca"] and "a"+"cb"=["acb","cab","cba"]
Zatem cała permutacja:
["abc","bac","bca","acb","cab","cba"]
Kod:
publicclassTest{staticSet<String> permutations;staticSet<String> result =newHashSet<String>();publicstaticSet<String> permutation(String string){
permutations =newHashSet<String>();int n = string.length();for(int i = n -1; i >=0; i--){
shuffle(string.charAt(i));}return permutations;}privatestaticvoid shuffle(char c){if(permutations.size()==0){
permutations.add(String.valueOf(c));}else{Iterator<String> it = permutations.iterator();for(int i =0; i < permutations.size(); i++){String temp1;for(; it.hasNext();){
temp1 = it.next();for(int k =0; k < temp1.length()+1; k +=1){StringBuilder sb =newStringBuilder(temp1);
sb.insert(k, c);
result.add(sb.toString());}}}
permutations = result;//'result' has to be refreshed so that in next run it doesn't contain stale values.
result =newHashSet<String>();}}publicstaticvoid main(String[] args){Set<String> result = permutation("abc");System.out.println("\nThere are total of "+ result.size()+" permutations:");Iterator<String> it = result.iterator();while(it.hasNext()){System.out.println(it.next());}}}
Jest to podobne do rozwiązania podanego tutaj: geeksforgeeks.org/… , obejmującego cofanie się i złożoność czasową O (n * n!).
Nakul Kumar
5
implementacja python
def getPermutation(s, prefix=''):if len(s)==0:
print prefix
for i in range(len(s)):
getPermutation(s[0:i]+s[i+1:len(s)],prefix+s[i])
getPermutation('abcd','')
gdy wejście jest pustym ciągiem, jedyną permutacją jest pusty ciąg. Wypróbuj każdą z liter w ciągu, ustawiając go jako pierwszą literę, a następnie znajdź wszystkie permutacje pozostałych liter za pomocą wywołania rekurencyjnego.
import java.util.ArrayList;import java.util.List;classPermutation{privatestaticList<String> permutation(String prefix,String str){List<String> permutations =newArrayList<>();int n = str.length();if(n ==0){
permutations.add(prefix);}else{for(int i =0; i < n; i++){
permutations.addAll(permutation(prefix + str.charAt(i), str.substring(i +1, n)+ str.substring(0, i)));}}return permutations;}publicstaticvoid main(String[] args){List<String> perms = permutation("","abcd");String[] array =newString[perms.size()];for(int i =0; i < perms.size(); i++){
array[i]= perms.get(i);}int x = array.length;for(finalString anArray : array){System.out.println(anArray);}}}
Podstawowa koncepcja: Podział długiej listy na mniejszą listę + rekurencja
Długa odpowiedź z przykładową listą [1, 2, 3, 4]:
Nawet w przypadku listy 4 to już trochę mylące, próbując wymienić wszystkie możliwe permutacje w twojej głowie, a to, co musimy zrobić, to właśnie tego uniknąć. Łatwo jest nam zrozumieć, jak wykonać wszystkie permutacje listy o rozmiarach 0, 1 i 2, więc wszystko, co musimy zrobić, to rozbić je na dowolny z tych rozmiarów i połączyć je poprawnie. Wyobraź sobie maszynę z jackpotem: ten algorytm zacznie się obracać od prawej do lewej i zapisze
zwraca pustą / listę 1, gdy rozmiar listy wynosi 0 lub 1
obsłużyć, gdy rozmiar listy wynosi 2 (np. [3, 4]), i wygenerować 2 permutacje ([3, 4] i [4, 3])
Dla każdego elementu zaznacz to jako ostatnie w ostatnim i znajdź wszystkie permutacje dla reszty elementu na liście. (np. połóż [4] na stole i ponownie wrzuć [1, 2, 3] do permutacji)
Teraz z całą permutacją są to dzieci, wróć na koniec listy (np .: [1, 2, 3] [, 4], [1, 3, 2] [, 4], [2, 3, 1] [, 4], ...)
/** Returns an array list containing all
* permutations of the characters in s. */publicstaticArrayList<String> permute(String s){ArrayList<String> perms =newArrayList<>();int slen = s.length();if(slen >0){// Add the first character from s to the perms array list.
perms.add(Character.toString(s.charAt(0)));// Repeat for all additional characters in s.for(int i =1; i < slen;++i){// Get the next character from s.char c = s.charAt(i);// For each of the strings currently in perms do the following:int size = perms.size();for(int j =0; j < size;++j){// 1. remove the stringString p = perms.remove(0);int plen = p.length();// 2. Add plen + 1 new strings to perms. Each new string// consists of the removed string with the character c// inserted into it at a unique location.for(int k =0; k <= plen;++k){
perms.add(p.substring(0, k)+ c + p.substring(k));}}}}return perms;}
Nie uważam tej odpowiedzi za przydatną, ponieważ nie zawiera żadnego wyjaśnienia i używa tego samego algorytmu, co kilka innych odpowiedzi, które zawierają wyjaśnienie.
Bernhard Barker
1
//Rotate and create words beginning with all letter possible and push to stack 1//Read from stack1 and for each word create words with other letters at the next location by rotation and so on /* eg : man
1. push1 - man, anm, nma
2. pop1 - nma , push2 - nam,nma
pop1 - anm , push2 - amn,anm
pop1 - man , push2 - mna,man
*/publicclassStringPermute{staticString str;staticString word;staticint top1 =-1;staticint top2 =-1;staticString[] stringArray1;staticString[] stringArray2;staticint strlength =0;publicstaticvoid main(String[] args)throwsIOException{System.out.println("Enter String : ");InputStreamReader isr =newInputStreamReader(System.in);BufferedReader bfr =newBufferedReader(isr);
str = bfr.readLine();
word = str;
strlength = str.length();int n =1;for(int i =1; i <= strlength; i++){
n = n * i;}
stringArray1 =newString[n];
stringArray2 =newString[n];
push(word,1);
doPermute();
display();}publicstaticvoid push(String word,int x){if(x ==1)
stringArray1[++top1]= word;else
stringArray2[++top2]= word;}publicstaticString pop(int x){if(x ==1)return stringArray1[top1--];elsereturn stringArray2[top2--];}publicstaticvoid doPermute(){for(int j = strlength; j >=2; j--)
popper(j);}publicstaticvoid popper(int length){// pop from stack1 , rotate each word n times and push to stack 2if(top1 >-1){while(top1 >-1){
word = pop(1);for(int j =0; j < length; j++){
rotate(length);
push(word,2);}}}// pop from stack2 , rotate each word n times w.r.t position and push to// stack 1else{while(top2 >-1){
word = pop(2);for(int j =0; j < length; j++){
rotate(length);
push(word,1);}}}}publicstaticvoid rotate(int position){char[] charstring =newchar[100];for(int j =0; j < word.length(); j++)
charstring[j]= word.charAt(j);int startpos = strlength - position;char temp = charstring[startpos];for(int i = startpos; i < strlength -1; i++){
charstring[i]= charstring[i +1];}
charstring[strlength -1]= temp;
word =newString(charstring).trim();}publicstaticvoid display(){int top;if(top1 >-1){while(top1 >-1)System.out.println(stringArray1[top1--]);}else{while(top2 >-1)System.out.println(stringArray2[top2--]);}}}
Innym prostym sposobem jest zapętlenie łańcucha, wybranie nieużywanego znaku i umieszczenie go w buforze, kontynuowanie pętli, aż rozmiar bufora będzie równy długości łańcucha. Bardziej podoba mi się to rozwiązanie do śledzenia wstecznego, ponieważ:
Łatwy do zrozumienia
Łatwo uniknąć powielania
Dane wyjściowe są sortowane
Oto kod Java:
List<String> permute(String str){if(str ==null){returnnull;}char[] chars = str.toCharArray();boolean[] used =newboolean[chars.length];List<String> res =newArrayList<String>();StringBuilder sb =newStringBuilder();Arrays.sort(chars);
helper(chars, used, sb, res);return res;}void helper(char[] chars,boolean[] used,StringBuilder sb,List<String> res){if(sb.length()== chars.length){
res.add(sb.toString());return;}for(int i =0; i < chars.length; i++){// avoid duplicatesif(i >0&& chars[i]== chars[i -1]&&!used[i -1]){continue;}// pick the character that has not used yetif(!used[i]){
used[i]=true;
sb.append(chars[i]);
helper(chars, used, sb, res);// back tracking
sb.deleteCharAt(sb.length()-1);
used[i]=false;}}}
Rekurencja nie jest konieczna, nawet jeśli możesz bezpośrednio obliczyć dowolną permutację , w tym rozwiązaniu zastosowano ogólne funkcje do permutacji dowolnej tablicy.
Implementacja Java, która drukuje wszystkie permutacje danego ciągu z uwzględnieniem duplikatów znaków i drukuje tylko unikalne znaki, jest następująca:
Można to zrobić iteracyjnie, po prostu wstawiając kolejno każdą literę łańcucha we wszystkich lokalizacjach poprzednich wyników częściowych.
Zaczynamy [A], który ze Bstaje [BA, AB], i C,[CBA, BCA, BAC, CAB, etc] .
Czas pracy byłoby O(n!), które dla przypadku testowego ABCD, jest1 x 2 x 3 x 4 .
W powyższym produkcie 1jest za A, 2jest za Bitp.
Próbka Dart:
void main(){String insertAt(String a,String b,int index){return a.substring(0, index)+ b + a.substring(index);}List<String>Permute(String word){
var letters = word.split('');
var p_list =[ letters.first ];for(var c in letters.sublist(1)){
var new_list =[];for(var p in p_list)for(int i =0; i <= p.length; i++)
new_list.add(insertAt(p, c, i));
p_list = new_list;}return p_list;}
print(Permute("ABCD"));}
Odpowiedzi:
(poprzez wprowadzenie do programowania w Javie )
źródło
n==0
, możesz zatrzymać poziom wcześniej on==1
i wydrukowaćprefix + str
.Użyj rekurencji.
źródło
Oto moje rozwiązanie oparte na książce „Cracking the Coding Interview” (P54):
Uruchomione wyjście ciągu „abcd”:
Krok 1: Scal [a] ib: [ba, ab]
Krok 2: Scal [ba, ab] ic: [cba, bca, bac, cab, acb, abc]
Krok 3: Scal [cba, bca, bac, cab, acb, abc] id: [dcba, cdba, cbda, cbad, dbca, bdca, bcda, bcad, dbac, bdac, badc, bacd, dcab, cdab, cadb , cabd, dacb, adcb, acdb, acbd, dabc, adbc, abdc, abcd]
źródło
Ze wszystkich rozwiązań podanych tutaj i na innych forach najbardziej podobał mi się Mark Byers. Ten opis naprawdę zmusił mnie do myślenia i samodzielnego kodowania. Szkoda, że nie mogę głosować na jego rozwiązanie, ponieważ jestem nowicjuszem.
W każdym razie tutaj jest moja implementacja jego opisu
Wolę to rozwiązanie przed pierwszym w tym wątku, ponieważ to rozwiązanie używa StringBuffer. Nie powiedziałbym, że moje rozwiązanie nie tworzy żadnego łańcucha tymczasowego (faktycznie robi to
system.out.println
tam, gdzietoString()
wywoływany jest StringBuffer). Ale po prostu uważam, że jest to lepsze niż pierwsze rozwiązanie, w którym powstaje zbyt wiele literałów łańcuchowych. Może być jakimś facetem od wydajności, który może to ocenić pod względem „pamięci” (na „czas” to już opóźnia się z powodu tej dodatkowej „wymiany”)źródło
if(index == str.length())
idoPerm(str, index + 1);
?currPos
Wydaje się tu zbędne.Bardzo podstawowym rozwiązaniem w Javie jest użycie rekurencji + zestawu (aby uniknąć powtórzeń), jeśli chcesz przechowywać i zwracać ciągi rozwiązania:
źródło
Wszyscy poprzedni współpracownicy wykonali świetną robotę wyjaśniając i udostępniając kod. Pomyślałem, że powinienem również podzielić się tym podejściem, ponieważ mogłoby to komuś pomóc. Rozwiązanie oparte jest na ( algorytm hałd )
Kilka rzeczy:
Zauważ, że ostatni element przedstawiony w programie Excel służy wyłącznie do lepszej wizualizacji logiki. Tak więc rzeczywiste wartości w ostatniej kolumnie wyniosłyby 2,1,0 (gdybyśmy uruchomili kod, ponieważ mamy do czynienia z tablicami, a tablice zaczynają się od 0).
Algorytm zamiany odbywa się na podstawie parzystych lub nieparzystych wartości bieżącej pozycji. Jest to bardzo zrozumiałe, jeśli spojrzysz na to, gdzie wywoływana jest metoda zamiany. Możesz zobaczyć, co się dzieje.
Oto co się dzieje:
źródło
Ten jest bez rekurencji
źródło
System.out.println(permute("AABBC").size());
wyświetla 45, ale w rzeczywistości 5! = 120Użyjmy danych wejściowych
abc
Jako przykład .Zacznij od ostatniego elementu (
c
) w zestawie (["c"]
), a następnie dodaj drugi ostatni element (b
) do jego przodu, końca i wszystkich możliwych pozycji na środku, tworząc go,["bc", "cb"]
a następnie w ten sam sposób doda następny element od back (a
) do każdego ciągu w zestawie, dzięki czemu:Zatem cała permutacja:
Kod:
źródło
Oto eleganckie, nierekurencyjne rozwiązanie O (n!):
źródło
Jednym z prostych rozwiązań może być po prostu zamiana znaków rekurencyjnie za pomocą dwóch wskaźników.
źródło
implementacja python
źródło
to działało dla mnie ..
źródło
Użyj rekurencji.
gdy wejście jest pustym ciągiem, jedyną permutacją jest pusty ciąg. Wypróbuj każdą z liter w ciągu, ustawiając go jako pierwszą literę, a następnie znajdź wszystkie permutacje pozostałych liter za pomocą wywołania rekurencyjnego.
źródło
Pozwól mi spróbować rozwiązać ten problem za pomocą Kotlin:
Podstawowa koncepcja: Podział długiej listy na mniejszą listę + rekurencja
Długa odpowiedź z przykładową listą [1, 2, 3, 4]:
Nawet w przypadku listy 4 to już trochę mylące, próbując wymienić wszystkie możliwe permutacje w twojej głowie, a to, co musimy zrobić, to właśnie tego uniknąć. Łatwo jest nam zrozumieć, jak wykonać wszystkie permutacje listy o rozmiarach 0, 1 i 2, więc wszystko, co musimy zrobić, to rozbić je na dowolny z tych rozmiarów i połączyć je poprawnie. Wyobraź sobie maszynę z jackpotem: ten algorytm zacznie się obracać od prawej do lewej i zapisze
źródło
źródło
źródło
Oto proste minimalistyczne rekurencyjne rozwiązanie w Javie:
źródło
Możemy użyć silni, aby dowiedzieć się, ile ciągów zaczyna się od konkretnej litery.
Przykład: weź dane wejściowe
abcd
.(3!) == 6
ciągi zaczynają się od każdej literyabcd
.źródło
Zrobiłem to poprzez podstawowe zrozumienie permutacji i wywoływania funkcji rekurencyjnych. Trwa to trochę czasu, ale odbywa się to niezależnie.
który generuje dane wyjściowe jako
[abc, acb, bac, bca, cab, cba]
.Podstawowa logika tego jest
Dla każdej postaci uważaj ją za pierwszą i znajdź kombinacje pozostałych postaci. np
[abc](Combination of abc)->
.a->[bc](a x Combination of (bc))->{abc,acb}
b->[ac](b x Combination of (ac))->{bac,bca}
c->[ab](c x Combination of (ab))->{cab,cba}
A następnie rekurencyjnie nazywając siebie
[bc]
,[ac]
i[ab]
niezależnie od siebie.źródło
Implementacja Java bez rekurencji
źródło
// wstaw każdy znak do tablicy arraylist
źródło
źródło
Innym prostym sposobem jest zapętlenie łańcucha, wybranie nieużywanego znaku i umieszczenie go w buforze, kontynuowanie pętli, aż rozmiar bufora będzie równy długości łańcucha. Bardziej podoba mi się to rozwiązanie do śledzenia wstecznego, ponieważ:
Oto kod Java:
Dane wejściowe: 1231
Lista wyjściowa: {1123, 1132, 1213, 1231, 1312, 1321, 2113, 2131, 2311, 3112, 3121, 3211}
Zauważyłem, że dane wyjściowe są posortowane i nie ma duplikatu wyników.
źródło
Rekurencja nie jest konieczna, nawet jeśli możesz bezpośrednio obliczyć dowolną permutację , w tym rozwiązaniu zastosowano ogólne funkcje do permutacji dowolnej tablicy.
Oto dobra informacja na temat tego algorytmu.
Dla C # twórców tutaj jest bardziej przydatna realizacja.
Algorytm ten ma złożoność czasową i przestrzenną O (N) do obliczania każdej permutacji .
źródło
Permutacja ciągu:
źródło
Oto kolejna prostsza metoda przeprowadzania permutacji łańcucha.
źródło
Implementacja Java, która drukuje wszystkie permutacje danego ciągu z uwzględnieniem duplikatów znaków i drukuje tylko unikalne znaki, jest następująca:
źródło
źródło
Można to zrobić iteracyjnie, po prostu wstawiając kolejno każdą literę łańcucha we wszystkich lokalizacjach poprzednich wyników częściowych.
Zaczynamy
[A]
, który zeB
staje[BA, AB]
, iC
,[CBA, BCA, BAC, CAB, etc]
.Czas pracy byłoby
O(n!)
, które dla przypadku testowegoABCD
, jest1 x 2 x 3 x 4
.W powyższym produkcie
1
jest zaA
,2
jest zaB
itp.Próbka Dart:
źródło
Oto implementacja Java:
http://ideone.com/nWPb3k
źródło