Какой элегантный способ найти все перестановки строки. Например, перестановка для ba, будет baи ab, но как насчет более длинной строки, такой как abcdefgh? Есть ли пример реализации Java?
Есть предположение, которое необходимо упомянуть. Персонажи уникальны. Например, для строки «aaaa» есть только один ответ. Чтобы получить более общий ответ, вы можете сохранить строки в наборе, чтобы избежать дублирования
Afshin Moazami
1
Допускается ли повторение символов или повторение символов? Может ли одна строка иметь несколько вхождений одного и того же символа?
Андерсон Грин
2
Прочитайте теорию (или, если, как и я, вы ленивы, перейдите на en.wikipedia.org/wiki/Permutation ) и реализуйте настоящий алгоритм. По сути, вы можете сгенерировать последовательность упорядочений элементов (тот факт, что это строка не имеет значения) и проходить их по порядку, пока не вернетесь к началу. Держитесь подальше от всего, что связано с рекурсией или строковыми манипуляциями.
CurtainDog
Ответы:
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));}}
Это не ракетостроение, я придумал почти такой же ответ. Незначительная настройка: вместо повторения до n==0, вы можете остановить уровень раньше n==1и распечатать prefix + str.
lambshaanxy
7
"Какова временная и пространственная сложность этого?" без какого-либо частичного кэширования ответов любой алгоритм, который выводит перестановку, равен o (n!), потому что набор результатов для вопроса перестановки является факториальным для ввода.
jeremyjjbrown
9
Элегантно, да. Но решение, которое преобразуется в массив char и заменяет его для генерации перестановок, потребует гораздо меньшего копирования и генерирует намного меньше мусора. Также этот алгоритм не учитывает повторяющиеся символы.
Джин
20
@AfshinMoazami Я думаю, что str.substring (i + 1, n) можно заменить на str.substring (i + 1). Использование str.substring (i) вызовет java.lang.StackOverflowError.
Ayusman
196
Используйте рекурсию.
Попробуйте каждую из букв по очереди в качестве первой буквы, а затем найдите все перестановки оставшихся букв, используя рекурсивный вызов.
Базовый случай, когда входные данные являются пустой строкой, единственной перестановкой является пустая строка.
Как вы можете добавить тип возвращаемого значения в метод permute? Компилятор не может определить тип возвращаемого значения этого метода на каждой итерации, даже если это, очевидно, тип String.
user1712095
Как вы обеспечиваете различные перестановки в этом методе?
Капад
70
Вот мое решение, основанное на идее книги «Взлом интервью» (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;}
Страница (71) в книге «Взлом кодирования», 6-е издание. :)
KarimIhab
5
Это действительно хорошее решение? Он основан на сохранении результатов в списке, поэтому для короткой входной строки он выходит из-под контроля.
Андроидер
что слияние делать?
Басаварадж Валикар
Он вставляет c в каждую возможную позицию каждой строки в списке, поэтому, если список содержит только ["b"] и c равен "a", результатом слияния является ["ab", "ba"], здесь то же самое решение со Swift gist.github. com / daniaDlbani / 3bc10e02541f9ba310d546040c5322fc
Дания Дельбани
53
Из всех решений, представленных здесь и на других форумах, мне больше всего понравился Марк Байерс. Это описание на самом деле заставило меня задуматься и написать его самому. Жаль, что я не могу оценить его решение, так как я новичок.
В любом случае вот моя реализация его описания
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);}}
Я предпочитаю это решение раньше, чем первое в этом потоке, потому что это решение использует StringBuffer. Я бы не сказал, что мое решение не создает никакой временной строки (на самом деле это происходит system.out.printlnтам, где вызывается метод toString()StringBuffer). Но я просто чувствую, что это лучше, чем первое решение, где создается слишком много строковых литералов. Может быть, какой-то парень из производительности может оценить это с точки зрения «памяти» (для «времени» он уже отстает из-за этого дополнительного «обмена»)
Почему бы просто не сделать if(index == str.length())и doPerm(str, index + 1);? currPosЗдесь кажется ненужным.
Robur_131
Извините, не могли бы вы подробнее остановиться на этом вопросе? Вы просто предлагаете не использовать дополнительные переменные currPos (используемые из-за множественных вхождений, а также читабельности), если нет, пожалуйста, вставьте решение, которое вы предлагаете посмотреть
srikanth yaradla
Ах, я понял, что вы имели в виду изменение базового условия с помощью прямой индексации. Работает отлично. Просто на решение, которое я представил, больше всего повлияли другие решения, которые часто пропускали усеченную строку, а не оригинал (случай 0 имеет смысл). Тем не менее, спасибо за указание. Посмотрим, смогу ли я отредактировать, прошло уже много лет с тех пор, как я зашел на этот сайт.
Срикант Ярадла
22
Основное решение в Java - использовать recursion + Set (чтобы избежать повторений), если вы хотите сохранить и вернуть строки решения:
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!), так как у нас есть n! перестановки в заданной строке длиной n.
Zok
17
Все предыдущие участники проделали большую работу, объясняя и предоставляя код. Я подумал, что тоже должен поделиться этим подходом, потому что он тоже может кому-то помочь Решение основано на алгоритме куч )
Пара вещей:
Обратите внимание, что последний элемент, который изображен в Excel, просто для того, чтобы помочь вам лучше визуализировать логику. Таким образом, фактические значения в последнем столбце были бы 2,1,0 (если бы мы запускали код, потому что имеем дело с массивами, а массивы начинаются с 0).
Алгоритм обмена происходит на основе четных или нечетных значений текущей позиции. Это самоочевидно, если вы посмотрите, где вызывается метод подкачки. Вы можете видеть, что происходит.
Вот что происходит:
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;}
это решение кажется неправильным System.out.println(permute("AABBC").size());отображает 45, но на самом деле 5! = 120
Младен Адамович
11
Давайте использовать вход abc в качестве примера.
Начните с последнего элемента ( c) в set ( ["c"]), затем добавьте второй последний элемент ( b) к его переднему, конечному и каждому возможному положению в середине, сделав его, ["bc", "cb"]а затем таким же образом добавьте следующий элемент от back ( a) до каждой строки в наборе, составляющей это:
"a"+"bc"=["abc","bac","bca"] and "a"+"cb"=["acb","cab","cba"]
Таким образом вся перестановка:
["abc","bac","bca","acb","cab","cba"]
Код:
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());}}}
Это похоже на решение, приведенное здесь: geeksforgeeks.org/… , включающее откат и сложность времени O (n * n!).
Накул Кумар
5
реализация 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','')
когда входные данные являются пустой строкой, единственная перестановка - пустая строка. Попробуйте для каждой буквы в строке сделать ее первой буквой, а затем найдите все перестановки оставшихся букв, используя рекурсивный вызов.
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);}}}
Основная концепция: разбить длинный список на меньший список + рекурсия
Длинный ответ с примером списка [1, 2, 3, 4]:
Даже для списка из 4-х уже запутывается попытка составить список всех возможных перестановок в вашей голове, и нам нужно именно этого избежать. Нам легко понять, как сделать все перестановки списка размером 0, 1 и 2, поэтому все, что нам нужно сделать, это разбить их на любой из этих размеров и правильно их объединить. Представьте себе машину с джекпотом: этот алгоритм начнет вращаться справа налево и запишет
вернуть пустой список 1, если размер списка равен 0 или 1
обрабатывать, когда размер списка равен 2 (например, [3, 4]), и генерировать 2 перестановки ([3, 4] и [4, 3])
Для каждого элемента отметьте его как последний в последнем и найдите все перестановки для оставшегося элемента в списке. (например, положить [4] на стол и снова бросить [1, 2, 3] в перестановку)
Теперь со всеми перестановками это дети, поставьте себя обратно в конец списка (например: [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;}
Я не нахожу этот ответ полезным , поскольку оно не содержит каких - либо объяснений , и он использует тот же алгоритм, что и некоторые другие ответы , которые делают дать объяснение.
Бернхард Баркер
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--]);}}}
Еще один простой способ - перебрать строку, выбрать символ, который еще не используется, и поместить его в буфер, продолжить цикл до тех пор, пока размер буфера не станет равным длине строки. Мне больше нравится это решение для отслеживания, потому что:
Легко понять
Легко избежать дублирования
Выход отсортирован
Вот код 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;}}}
Рекурсия не требуется, даже если вы можете вычислить любую перестановку напрямую , в этом решении используются универсальные переменные для перестановки любого массива.
Java-реализация для печати всех перестановок данной строки с учетом повторяющихся символов и печати только уникальных символов выглядит следующим образом:
Это можно сделать итеративно, просто вставляя каждую букву строки по очереди во все места предыдущих частичных результатов.
Начнем с того [A], что с Bстановится [BA, AB], и с C,[CBA, BCA, BAC, CAB, etc] .
Время работы будет O(n!), что, для теста ABCD, является1 x 2 x 3 x 4 .
В приведенном выше продукте, 1для A, 2дляB и т. Д.
Образец дротика:
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"));}
Ответы:
(через введение в программирование на Java )
источник
n==0
, вы можете остановить уровень раньшеn==1
и распечататьprefix + str
.Используйте рекурсию.
источник
Вот мое решение, основанное на идее книги «Взлом интервью» (P54):
Запуск вывода строки "abcd":
Шаг 1: Объедините [a] и b: [ba, ab]
Шаг 2: Объедините [ba, ab] и c: [cba, bca, bac, cab, acb, abc]
Шаг 3: Объедините [cba, bca, bac, cab, acb, abc] и d: [dcba, cdba, cbda, cbad, dbca, bdca, bcda, bcad, dbac, bdac, badc, bacd, dcab, cdab, cadb , cabd, dacb, adcb, acdb, acbd, dabc, adbc, abdc, abcd]
источник
Из всех решений, представленных здесь и на других форумах, мне больше всего понравился Марк Байерс. Это описание на самом деле заставило меня задуматься и написать его самому. Жаль, что я не могу оценить его решение, так как я новичок.
В любом случае вот моя реализация его описания
Я предпочитаю это решение раньше, чем первое в этом потоке, потому что это решение использует StringBuffer. Я бы не сказал, что мое решение не создает никакой временной строки (на самом деле это происходит
system.out.println
там, где вызывается методtoString()
StringBuffer). Но я просто чувствую, что это лучше, чем первое решение, где создается слишком много строковых литералов. Может быть, какой-то парень из производительности может оценить это с точки зрения «памяти» (для «времени» он уже отстает из-за этого дополнительного «обмена»)источник
if(index == str.length())
иdoPerm(str, index + 1);
?currPos
Здесь кажется ненужным.Основное решение в Java - использовать recursion + Set (чтобы избежать повторений), если вы хотите сохранить и вернуть строки решения:
источник
Все предыдущие участники проделали большую работу, объясняя и предоставляя код. Я подумал, что тоже должен поделиться этим подходом, потому что он тоже может кому-то помочь Решение основано на алгоритме куч )
Пара вещей:
Обратите внимание, что последний элемент, который изображен в Excel, просто для того, чтобы помочь вам лучше визуализировать логику. Таким образом, фактические значения в последнем столбце были бы 2,1,0 (если бы мы запускали код, потому что имеем дело с массивами, а массивы начинаются с 0).
Алгоритм обмена происходит на основе четных или нечетных значений текущей позиции. Это самоочевидно, если вы посмотрите, где вызывается метод подкачки. Вы можете видеть, что происходит.
Вот что происходит:
источник
Этот без рекурсии
источник
System.out.println(permute("AABBC").size());
отображает 45, но на самом деле 5! = 120Давайте использовать вход
abc
в качестве примера.Начните с последнего элемента (
c
) в set (["c"]
), затем добавьте второй последний элемент (b
) к его переднему, конечному и каждому возможному положению в середине, сделав его,["bc", "cb"]
а затем таким же образом добавьте следующий элемент от back (a
) до каждой строки в наборе, составляющей это:Таким образом вся перестановка:
Код:
источник
Вот элегантное нерекурсивное решение O (n!):
источник
Одним из простых решений может быть простое рекурсивное изменение символов с помощью двух указателей.
источник
реализация Python
источник
это сработало для меня ..
источник
Используйте рекурсию.
когда входные данные являются пустой строкой, единственная перестановка - пустая строка. Попробуйте для каждой буквы в строке сделать ее первой буквой, а затем найдите все перестановки оставшихся букв, используя рекурсивный вызов.
источник
Позвольте мне попытаться решить эту проблему с Kotlin:
Основная концепция: разбить длинный список на меньший список + рекурсия
Длинный ответ с примером списка [1, 2, 3, 4]:
Даже для списка из 4-х уже запутывается попытка составить список всех возможных перестановок в вашей голове, и нам нужно именно этого избежать. Нам легко понять, как сделать все перестановки списка размером 0, 1 и 2, поэтому все, что нам нужно сделать, это разбить их на любой из этих размеров и правильно их объединить. Представьте себе машину с джекпотом: этот алгоритм начнет вращаться справа налево и запишет
источник
источник
источник
Вот простое минималистское рекурсивное решение в Java:
источник
Мы можем использовать factorial, чтобы найти, сколько строк начинаются с определенной буквы.
Пример: взять ввод
abcd
.(3!) == 6
Строки начинаются с каждой буквыabcd
.источник
Это то, что я сделал благодаря базовому пониманию перестановок и рекурсивного вызова функций. Занимает немного времени, но это делается независимо.
который генерирует вывод как
[abc, acb, bac, bca, cab, cba]
.Основная логика позади это
Для каждого символа рассмотрите его как 1-ый символ и найдите комбинации оставшихся символов. например
[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}
А затем рекурсивно вызывая каждый
[bc]
,[ac]
и[ab]
независимо друг от друга.источник
Реализация Java без рекурсии
источник
// вставляем каждый символ в массив
источник
источник
Еще один простой способ - перебрать строку, выбрать символ, который еще не используется, и поместить его в буфер, продолжить цикл до тех пор, пока размер буфера не станет равным длине строки. Мне больше нравится это решение для отслеживания, потому что:
Вот код Java:
Входная строка: 1231
Список вывода: {1123, 1132, 1213, 1231, 1312, 1321, 2113, 2131, 2311, 3112, 3121, 3211}
Заметил, что выходные данные отсортированы, а дублированный результат отсутствует.
источник
Рекурсия не требуется, даже если вы можете вычислить любую перестановку напрямую , в этом решении используются универсальные переменные для перестановки любого массива.
Вот хорошая информация об этом algorihtm.
Для разработчиков на C # здесь есть более полезная реализация.
Этот алгоритм имеет O (N) временную и пространственную сложность для вычисления каждой перестановки .
источник
Перестановка строки:
источник
Вот еще один более простой способ перестановки строк.
источник
Java-реализация для печати всех перестановок данной строки с учетом повторяющихся символов и печати только уникальных символов выглядит следующим образом:
источник
источник
Это можно сделать итеративно, просто вставляя каждую букву строки по очереди во все места предыдущих частичных результатов.
Начнем с того
[A]
, что сB
становится[BA, AB]
, и сC
,[CBA, BCA, BAC, CAB, etc]
.Время работы будет
O(n!)
, что, для тестаABCD
, является1 x 2 x 3 x 4
.В приведенном выше продукте,
1
дляA
,2
дляB
и т. Д.Образец дротика:
источник
Вот реализация Java:
http://ideone.com/nWPb3k
источник