Генерация всех перестановок данной строки

418

Какой элегантный способ найти все перестановки строки. Например, перестановка для ba, будет baи ab, но как насчет более длинной строки, такой как abcdefgh? Есть ли пример реализации Java?

GurdeepS
источник
3
Здесь есть много ответов: stackoverflow.com/questions/361/…
Марек Сапота
это очень популярный вопрос. Вы можете посмотреть здесь: careercup.com/question?id=3861299
JJunior
9
Есть предположение, которое необходимо упомянуть. Персонажи уникальны. Например, для строки «aaaa» есть только один ответ. Чтобы получить более общий ответ, вы можете сохранить строки в наборе, чтобы избежать дублирования
Afshin Moazami
1
Допускается ли повторение символов или повторение символов? Может ли одна строка иметь несколько вхождений одного и того же символа?
Андерсон Грин
2
Прочитайте теорию (или, если, как и я, вы ленивы, перейдите на en.wikipedia.org/wiki/Permutation ) и реализуйте настоящий алгоритм. По сути, вы можете сгенерировать последовательность упорядочений элементов (тот факт, что это строка не имеет значения) и проходить их по порядку, пока не вернетесь к началу. Держитесь подальше от всего, что связано с рекурсией или строковыми манипуляциями.
CurtainDog

Ответы:

601
public static void permutation(String str) { 
    permutation("", str); 
}

private static void 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));
    }
}

(через введение в программирование на Java )

SuperJulietta
источник
67
Похоже, что решение приходит отсюда introcs.cs.princeton.edu/java/23recursion/…
кибер-монах
48
Это не ракетостроение, я придумал почти такой же ответ. Незначительная настройка: вместо повторения до 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

Используйте рекурсию.

  • Попробуйте каждую из букв по очереди в качестве первой буквы, а затем найдите все перестановки оставшихся букв, используя рекурсивный вызов.
  • Базовый случай, когда входные данные являются пустой строкой, единственной перестановкой является пустая строка.
Марк Байерс
источник
3
Как вы можете добавить тип возвращаемого значения в метод permute? Компилятор не может определить тип возвращаемого значения этого метода на каждой итерации, даже если это, очевидно, тип String.
user1712095
Как вы обеспечиваете различные перестановки в этом методе?
Капад
70

Вот мое решение, основанное на идее книги «Взлом интервью» (P54):

/**
 * List permutations of a string.
 * 
 * @param s the input string
 * @return  the list of permutations
 */
public static ArrayList<String> permutation(String s) {
    // The result
    ArrayList<String> res = new ArrayList<String>();
    // If input string's length is 1, return {s}
    if (s.length() == 1) {
        res.add(s);
    } else if (s.length() > 1) {
        int lastIndex = s.length() - 1;
        // Find out the last character
        String last = s.substring(lastIndex);
        // Rest of the string
        String 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" ... }
 */
public static ArrayList<String> merge(ArrayList<String> list, String c) {
    ArrayList<String> res = new ArrayList<>();
    // Loop through all the string in the list
    for (String s : list) {
        // For each string, insert the last character to all possible positions
        // and add them to the new list
        for (int i = 0; i <= s.length(); ++i) {
            String ps = new StringBuffer(s).insert(i, c).toString();
            res.add(ps);
        }
    }
    return res;
}

Запуск вывода строки "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]

jeantimex
источник
Страница (71) в книге «Взлом кодирования», 6-е издание. :)
KarimIhab
5
Это действительно хорошее решение? Он основан на сохранении результатов в списке, поэтому для короткой входной строки он выходит из-под контроля.
Андроидер
что слияние делать?
Басаварадж Валикар
Он вставляет c в каждую возможную позицию каждой строки в списке, поэтому, если список содержит только ["b"] и c равен "a", результатом слияния является ["ab", "ba"], здесь то же самое решение со Swift gist.github. com / daniaDlbani / 3bc10e02541f9ba310d546040c5322fc
Дания Дельбани
53

Из всех решений, представленных здесь и на других форумах, мне больше всего понравился Марк Байерс. Это описание на самом деле заставило меня задуматься и написать его самому. Жаль, что я не могу оценить его решение, так как я новичок.
В любом случае вот моя реализация его описания

public class PermTest {

    public static void main(String[] args) throws Exception {
        String str = "abcdef";
        StringBuffer strBuf = new StringBuffer(str);
        doPerm(strBuf,0);
    }

    private static void 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
            }
        }
    }

    private  static void 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 (чтобы избежать повторений), если вы хотите сохранить и вернуть строки решения:

public static Set<String> generatePerm(String input)
{
    Set<String> set = new HashSet<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;
}
опустошитель
источник
2
Какова временная сложность этого алогрита?
Асисаху
1
@ashisahu O (n!), так как у нас есть n! перестановки в заданной строке длиной n.
Zok
17

Все предыдущие участники проделали большую работу, объясняя и предоставляя код. Я подумал, что тоже должен поделиться этим подходом, потому что он тоже может кому-то помочь Решение основано на алгоритме куч )

Пара вещей:

  1. Обратите внимание, что последний элемент, который изображен в Excel, просто для того, чтобы помочь вам лучше визуализировать логику. Таким образом, фактические значения в последнем столбце были бы 2,1,0 (если бы мы запускали код, потому что имеем дело с массивами, а массивы начинаются с 0).

  2. Алгоритм обмена происходит на основе четных или нечетных значений текущей позиции. Это самоочевидно, если вы посмотрите, где вызывается метод подкачки. Вы можете видеть, что происходит.

Вот что происходит: введите описание изображения здесь

public static void main(String[] args) {

        String ourword = "abc";
        String[] ourArray = ourword.split("");
        permute(ourArray, ourArray.length);

    }

    private static void swap(String[] ourarray, int right, int left) {
        String temp = ourarray[right];
        ourarray[right] = ourarray[left];
        ourarray[left] = temp;
    }

    public static void 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 position
                if (currentPosition % 2 == 1) {
                    swap(ourArray, 0, currentPosition - 1);
                } else {
                    swap(ourArray, i, currentPosition - 1);
                }
            }
        }
    }
grepit
источник
11

Этот без рекурсии

public static void permute(String s) {
    if(null==s || s.isEmpty()) {
        return;
    }

    // List containing words formed in each iteration 
    List<String> strings = new LinkedList<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 list
    List<String> tempList = new LinkedList<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)
 */
private static Set<String> merge(Character c,  String s) {
    if(s==null || s.isEmpty()) {
        return null;
    }

    int len = s.length();
    StringBuilder sb = new StringBuilder();
    Set<String> list = new HashSet<String>();

    for(int i=0; i<= len; i++) {
        sb = new StringBuilder();
        sb.append(s.substring(0, i) + c + s.substring(i, len));
        list.add(sb.toString());
    }

    return list;
}
Jeya
источник
это решение кажется неправильным 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"]

Код:

public class Test 
{
    static Set<String> permutations;
    static Set<String> result = new HashSet<String>();

    public static Set<String> permutation(String string) {
        permutations = new HashSet<String>();

        int n = string.length();
        for (int i = n - 1; i >= 0; i--) 
        {
            shuffle(string.charAt(i));
        }
        return permutations;
    }

    private static void 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 = new StringBuilder(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 = new HashSet<String>();
        }
    }

    public static void 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());
        }
    }
}
Вихан Верма
источник
1
Мне понравилось ваше решение. Очень интуитивно понятно и хорошо объяснено. Большое спасибо.
user2585781
9

Вот элегантное нерекурсивное решение O (n!):

public static StringBuilder[] permutations(String s) {
        if (s.length() == 0)
            return null;
        int length = fact(s.length());
        StringBuilder[] sb = new StringBuilder[length];
        for (int i = 0; i < length; i++) {
            sb[i] = new StringBuilder();
        }
        for (int i = 0; i < s.length(); i++) {
            char ch = s.charAt(i);
            int times = length / (i + 1);
            for (int j = 0; j < times; j++) {
                for (int k = 0; k < length / times; k++) {
                    sb[j * length / times + k].insert(k, ch);
                }
            }
        }
        return sb;
    }
Адилли Адиль
источник
Это решение работает, только если слово содержит менее 4 букв, в противном случае только половина приведенного массива содержит уникальные слова.
Максим Максимов
5

Одним из простых решений может быть простое рекурсивное изменение символов с помощью двух указателей.

public static void main(String[] args)
{
    String str="abcdefgh";
    perm(str);
}
public static void perm(String str)
{  char[] char_arr=str.toCharArray();
    helper(char_arr,0);
}
public static void helper(char[] char_arr, int i)
{
    if(i==char_arr.length-1)
    {
        // print the shuffled string 
            String str="";
            for(int j=0; j<char_arr.length; j++)
            {
                str=str+char_arr[j];
            }
            System.out.println(str);
    }
    else
    {
    for(int j=i; j<char_arr.length; j++)
    {
        char tmp = char_arr[i];
        char_arr[i] = char_arr[j];
        char_arr[j] = tmp;
        helper(char_arr,i+1);
        char tmp1 = char_arr[i];
        char_arr[i] = char_arr[j];
        char_arr[j] = tmp1;
    }
}
}
Кэти
источник
Это похоже на решение, приведенное здесь: 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','')
riteshkasat
источник
4

это сработало для меня ..

import java.util.Arrays;

public class StringPermutations{
    public static void main(String args[]) {
        String inputString = "ABC";
        permute(inputString.toCharArray(), 0, inputString.length()-1);
    }

    public static void permute(char[] ary, int startIndex, int endIndex) {
        if(startIndex == endIndex){
            System.out.println(String.valueOf(ary));
        }else{
            for(int i=startIndex;i<=endIndex;i++) {
                 swap(ary, startIndex, i );
                 permute(ary, startIndex+1, endIndex);
                 swap(ary, startIndex, i );
            }
        }
    }

    public static void swap(char[] ary, int x, int y) {
        char temp = ary[x];
        ary[x] = ary[y];
        ary[y] = temp;
    }
}
Арун Кумар Мудрабойна
источник
3

Используйте рекурсию.

когда входные данные являются пустой строкой, единственная перестановка - пустая строка. Попробуйте для каждой буквы в строке сделать ее первой буквой, а затем найдите все перестановки оставшихся букв, используя рекурсивный вызов.

import java.util.ArrayList;
import java.util.List;

class Permutation {
    private static List<String> permutation(String prefix, String str) {
        List<String> permutations = new ArrayList<>();
        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;
    }

    public static void main(String[] args) {
        List<String> perms = permutation("", "abcd");

        String[] array = new String[perms.size()];
        for (int i = 0; i < perms.size(); i++) {
            array[i] = perms.get(i);
        }

        int x = array.length;

        for (final String anArray : array) {
            System.out.println(anArray);
        }
    }
}
coder101
источник
3

Позвольте мне попытаться решить эту проблему с Kotlin:

fun <T> List<T>.permutations(): List<List<T>> {
    //escape case
    if (this.isEmpty()) return emptyList()

    if (this.size == 1) return listOf(this)

    if (this.size == 2) return listOf(listOf(this.first(), this.last()), listOf(this.last(), this.first()))

    //recursive case
    return this.flatMap { lastItem ->
        this.minus(lastItem).permutations().map { it.plus(lastItem) }
    }
}

Основная концепция: разбить длинный список на меньший список + рекурсия

Длинный ответ с примером списка [1, 2, 3, 4]:

Даже для списка из 4-х уже запутывается попытка составить список всех возможных перестановок в вашей голове, и нам нужно именно этого избежать. Нам легко понять, как сделать все перестановки списка размером 0, 1 и 2, поэтому все, что нам нужно сделать, это разбить их на любой из этих размеров и правильно их объединить. Представьте себе машину с джекпотом: этот алгоритм начнет вращаться справа налево и запишет

  1. вернуть пустой список 1, если размер списка равен 0 или 1
  2. обрабатывать, когда размер списка равен 2 (например, [3, 4]), и генерировать 2 перестановки ([3, 4] и [4, 3])
  3. Для каждого элемента отметьте его как последний в последнем и найдите все перестановки для оставшегося элемента в списке. (например, положить [4] на стол и снова бросить [1, 2, 3] в перестановку)
  4. Теперь со всеми перестановками это дети, поставьте себя обратно в конец списка (например: [1, 2, 3] [, 4], [1, 3, 2] [, 4], [2, 3, 1] [, 4], ...)
Луи Цай
источник
2
import java.io.IOException;
import java.util.ArrayList;
import java.util.Scanner;
public class hello {
    public static void main(String[] args) throws IOException {
        hello h = new hello();
        h.printcomp();
    }
      int fact=1;
    public void factrec(int a,int k){
        if(a>=k)
        {fact=fact*k;
        k++;
        factrec(a,k);
        }
        else
        {System.out.println("The string  will have "+fact+" permutations");
        }
        }
    public void printcomp(){
        String str;
        int k;
        Scanner in = new Scanner(System.in);
        System.out.println("enter the string whose permutations has to b found");
        str=in.next();
        k=str.length();
        factrec(k,1);
        String[] arr =new String[fact];
        char[] array = str.toCharArray();
        while(p<fact)
        printcomprec(k,array,arr);
            // if incase u need array containing all the permutation use this
            //for(int d=0;d<fact;d++)         
        //System.out.println(arr[d]);
    }
    int y=1;
    int p = 0;
    int g=1;
    int z = 0;
    public void printcomprec(int k,char array[],String arr[]){
        for (int l = 0; l < k; l++) {
            for (int b=0;b<k-1;b++){
            for (int i=1; i<k-g; i++) {
                char temp;
                String stri = "";
                temp = array[i];
                array[i] = array[i + g];
                array[i + g] = temp;
                for (int j = 0; j < k; j++)
                    stri += array[j];
                arr[z] = stri;
                System.out.println(arr[z] + "   " + p++);
                z++;
            }
            }
            char temp;
            temp=array[0];
            array[0]=array[y];
            array[y]=temp;
            if (y >= k-1)
                y=y-(k-1);
            else
                y++;
        }
        if (g >= k-1)
            g=1;
        else
            g++;
    }

}
Энтони Джонсон
источник
2
/** Returns an array list containing all
 * permutations of the characters in s. */
public static ArrayList<String> permute(String s) {
    ArrayList<String> perms = new ArrayList<>();
    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 string
                String 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;
}
Barzee
источник
2

Вот простое минималистское рекурсивное решение в Java:

public static ArrayList<String> permutations(String s) {
    ArrayList<String> out = new ArrayList<String>();
    if (s.length() == 1) {
        out.add(s);
        return out;
    }
    char first = s.charAt(0);
    String rest = s.substring(1);
    for (String permutation : permutations(rest)) {
        out.addAll(insertAtAllPositions(first, permutation));
    }
    return out;
}
public static ArrayList<String> insertAtAllPositions(char ch, String s) {
    ArrayList<String> out = new ArrayList<String>();
    for (int i = 0; i <= s.length(); ++i) {
        String inserted = s.substring(0, i) + ch + s.substring(i);
        out.add(inserted);
    }
    return out;
}
Джей Тейлор
источник
2

Мы можем использовать factorial, чтобы найти, сколько строк начинаются с определенной буквы.

Пример: взять ввод abcd. (3!) == 6Строки начинаются с каждой буквы abcd.

static public int facts(int x){
    int sum = 1;
    for (int i = 1; i < x; i++) {
        sum *= (i+1);
    }
    return sum;
}

public static void permutation(String str) {
    char[] str2 = str.toCharArray();
    int n = str2.length;
    int permutation = 0;
    if (n == 1) {
        System.out.println(str2[0]);
    } else if (n == 2) {
        System.out.println(str2[0] + "" + str2[1]);
        System.out.println(str2[1] + "" + str2[0]);
    } else {
        for (int i = 0; i < n; i++) {
            if (true) {
                char[] str3 = str.toCharArray();
                char temp = str3[i];
                str3[i] = str3[0];
                str3[0] = temp;
                str2 = str3;
            }

            for (int j = 1, count = 0; count < facts(n-1); j++, count++) {
                if (j != n-1) {
                    char temp1 = str2[j+1];
                    str2[j+1] = str2[j];
                    str2[j] = temp1;
                } else {
                    char temp1 = str2[n-1];
                    str2[n-1] = str2[1];
                    str2[1] = temp1;
                    j = 1;
                } // end of else block
                permutation++;
                System.out.print("permutation " + permutation + " is   -> ");
                for (int k = 0; k < n; k++) {
                    System.out.print(str2[k]);
                } // end of loop k
                System.out.println();
            } // end of loop j
        } // end of loop i
    }
}
user1685821
источник
2

Это то, что я сделал благодаря базовому пониманию перестановок и рекурсивного вызова функций. Занимает немного времени, но это делается независимо.

public class LexicographicPermutations {

public static void main(String[] args) {
    // TODO Auto-generated method stub
    String s="abc";
    List<String>combinations=new ArrayList<String>();
    combinations=permutations(s);
    Collections.sort(combinations);
    System.out.println(combinations);
}

private static List<String> permutations(String s) {
    // TODO Auto-generated method stub
    List<String>combinations=new ArrayList<String>();
    if(s.length()==1){
        combinations.add(s);
    }
    else{
        for(int i=0;i<s.length();i++){
            List<String>temp=permutations(s.substring(0, i)+s.substring(i+1));
            for (String string : temp) {
                combinations.add(s.charAt(i)+string);
            }
        }
    }
    return combinations;
}}

который генерирует вывод как[abc, acb, bac, bca, cab, cba] .

Основная логика позади это

Для каждого символа рассмотрите его как 1-ый символ и найдите комбинации оставшихся символов. например [abc](Combination of abc)->.

  1. a->[bc](a x Combination of (bc))->{abc,acb}
  2. b->[ac](b x Combination of (ac))->{bac,bca}
  3. c->[ab](c x Combination of (ab))->{cab,cba}

А затем рекурсивно вызывая каждый [bc], [ac]и [ab]независимо друг от друга.

Шаббир Эссаджи
источник
2

Реализация Java без рекурсии

public Set<String> permutate(String s){
    Queue<String> permutations = new LinkedList<String>();
    Set<String> v = new HashSet<String>();
    permutations.add(s);

    while(permutations.size()!=0){
        String str = permutations.poll();
        if(!v.contains(str)){
            v.add(str);
            for(int i = 0;i<str.length();i++){
                String c = String.valueOf(str.charAt(i));
                permutations.add(str.substring(i+1) + c +  str.substring(0,i));
            }
        }
    }
    return v;
}
Хади Элмоги
источник
1

// вставляем каждый символ в массив

static ArrayList al = new ArrayList();

private static void findPermutation (String str){
    for (int k = 0; k < str.length(); k++) {
        addOneChar(str.charAt(k));
    }
}

//insert one char into ArrayList
private static void addOneChar(char ch){
    String lastPerStr;
    String tempStr;
    ArrayList locAl = new ArrayList();
    for (int i = 0; i < al.size(); i ++ ){
        lastPerStr = al.get(i).toString();
        //System.out.println("lastPerStr: " + lastPerStr);
        for (int j = 0; j <= lastPerStr.length(); j++) {
            tempStr = lastPerStr.substring(0,j) + ch + 
                    lastPerStr.substring(j, lastPerStr.length());
            locAl.add(tempStr);
            //System.out.println("tempStr: " + tempStr);
        }
    }
    if(al.isEmpty()){
        al.add(ch);
    } else {
        al.clear();
        al = locAl;
    }
}

private static void printArrayList(ArrayList al){
    for (int i = 0; i < al.size(); i++) {
        System.out.print(al.get(i) + "  ");
    }
}
Дэвид Ли
источник
Я не нахожу этот ответ полезным , поскольку оно не содержит каких - либо объяснений , и он использует тот же алгоритм, что и некоторые другие ответы , которые делают дать объяснение.
Бернхард Баркер
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
*/

public class StringPermute {

    static String str;
    static String word;
    static int top1 = -1;
    static int top2 = -1;
    static String[] stringArray1;
    static String[] stringArray2;
    static int strlength = 0;

    public static void main(String[] args) throws IOException {
        System.out.println("Enter String : ");
        InputStreamReader isr = new InputStreamReader(System.in);
        BufferedReader bfr = new BufferedReader(isr);
        str = bfr.readLine();
        word = str;
        strlength = str.length();
        int n = 1;
        for (int i = 1; i <= strlength; i++) {
            n = n * i;
        }
        stringArray1 = new String[n];
        stringArray2 = new String[n];
        push(word, 1);
        doPermute();
        display();
    }

    public static void push(String word, int x) {
        if (x == 1)
            stringArray1[++top1] = word;
        else
            stringArray2[++top2] = word;
    }

    public static String pop(int x) {
        if (x == 1)
            return stringArray1[top1--];
        else
            return stringArray2[top2--];
    }

    public static void doPermute() {

        for (int j = strlength; j >= 2; j--)
            popper(j);

    }

    public static void popper(int length) {
        // pop from stack1 , rotate each word n times and push to stack 2
        if (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 1
        else {
            while (top2 > -1) {
                word = pop(2);
                for (int j = 0; j < length; j++) {
                    rotate(length);
                    push(word, 1);
                }
            }
        }

    }

    public static void rotate(int position) {
        char[] charstring = new char[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 = new String(charstring).trim();
    }

    public static void display() {
        int top;
        if (top1 > -1) {
            while (top1 > -1)
                System.out.println(stringArray1[top1--]);
        } else {
            while (top2 > -1)
                System.out.println(stringArray2[top2--]);
        }
    }
}
НЯЦ
источник
1

Еще один простой способ - перебрать строку, выбрать символ, который еще не используется, и поместить его в буфер, продолжить цикл до тех пор, пока размер буфера не станет равным длине строки. Мне больше нравится это решение для отслеживания, потому что:

  1. Легко понять
  2. Легко избежать дублирования
  3. Выход отсортирован

Вот код Java:

List<String> permute(String str) {
  if (str == null) {
    return null;
  }

  char[] chars = str.toCharArray();
  boolean[] used = new boolean[chars.length];

  List<String> res = new ArrayList<String>();
  StringBuilder sb = new StringBuilder();

  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 duplicates
    if (i > 0 && chars[i] == chars[i - 1] && !used[i - 1]) {
      continue;
    }

    // pick the character that has not used yet
    if (!used[i]) {
      used[i] = true;
      sb.append(chars[i]);

      helper(chars, used, sb, res);

      // back tracking
      sb.deleteCharAt(sb.length() - 1);
      used[i] = false;
    }
  }
}

Входная строка: 1231

Список вывода: {1123, 1132, 1213, 1231, 1312, 1321, 2113, 2131, 2311, 3112, 3121, 3211}

Заметил, что выходные данные отсортированы, а дублированный результат отсутствует.

jeantimex
источник
1

Рекурсия не требуется, даже если вы можете вычислить любую перестановку напрямую , в этом решении используются универсальные переменные для перестановки любого массива.

Вот хорошая информация об этом algorihtm.

Для разработчиков на C # здесь есть более полезная реализация.

public static void main(String[] args) {
    String word = "12345";

    Character[] array = ArrayUtils.toObject(word.toCharArray());
    long[] factorials = Permutation.getFactorials(array.length + 1);

    for (long i = 0; i < factorials[array.length]; i++) {
        Character[] permutation = Permutation.<Character>getPermutation(i, array, factorials);
        printPermutation(permutation);
    }
}

private static void printPermutation(Character[] permutation) {
    for (int i = 0; i < permutation.length; i++) {
        System.out.print(permutation[i]);
    }
    System.out.println();
}

Этот алгоритм имеет O (N) временную и пространственную сложность для вычисления каждой перестановки .

public class Permutation {
    public static <T> T[] getPermutation(long permutationNumber, T[] array, long[] factorials) {
        int[] sequence = generateSequence(permutationNumber, array.length - 1, factorials);
        T[] permutation = generatePermutation(array, sequence);

        return permutation;
    }

    public static <T> T[] generatePermutation(T[] array, int[] sequence) {
        T[] clone = array.clone();

        for (int i = 0; i < clone.length - 1; i++) {
            swap(clone, i, i + sequence[i]);
        }

        return clone;
    }

    private static int[] generateSequence(long permutationNumber, int size, long[] factorials) {
        int[] sequence = new int[size];

        for (int j = 0; j < sequence.length; j++) {
            long factorial = factorials[sequence.length - j];
            sequence[j] = (int) (permutationNumber / factorial);
            permutationNumber = (int) (permutationNumber % factorial);
        }

        return sequence;
    }

    private static <T> void swap(T[] array, int i, int j) {
        T t = array[i];
        array[i] = array[j];
        array[j] = t;
    }

    public static long[] getFactorials(int length) {
        long[] factorials = new long[length];
        long factor = 1;

        for (int i = 0; i < length; i++) {
            factor *= i <= 1 ? 1 : i;
            factorials[i] = factor;
        }

        return factorials;
    }
}
нахер
источник
1

Перестановка строки:

public static void main(String args[]) {
    permu(0,"ABCD");
}

static void permu(int fixed,String s) {
    char[] chr=s.toCharArray();
    if(fixed==s.length())
        System.out.println(s);
    for(int i=fixed;i<s.length();i++) {
        char c=chr[i];
        chr[i]=chr[fixed];
        chr[fixed]=c;
        permu(fixed+1,new String(chr));
    }   
}
sakivns
источник
1

Вот еще один более простой способ перестановки строк.

public class Solution4 {
public static void main(String[] args) {
    String  a = "Protijayi";
  per(a, 0);

}

static void per(String a  , int start ) {
      //bse case;
    if(a.length() == start) {System.out.println(a);}
    char[] ca = a.toCharArray();
    //swap 
    for (int i = start; i < ca.length; i++) {
        char t = ca[i];
        ca[i] = ca[start];
        ca[start] = t;
        per(new String(ca),start+1);
    }

}//per

}
Судипта Датта
источник
1

Java-реализация для печати всех перестановок данной строки с учетом повторяющихся символов и печати только уникальных символов выглядит следующим образом:

import java.util.Set;
import java.util.HashSet;

public class PrintAllPermutations2
{
    public static void main(String[] args)
    {
        String str = "AAC";

    PrintAllPermutations2 permutation = new PrintAllPermutations2();

    Set<String> uniqueStrings = new HashSet<>();

    permutation.permute("", str, uniqueStrings);
}

void permute(String prefixString, String s, Set<String> set)
{
    int n = s.length();

    if(n == 0)
    {
        if(!set.contains(prefixString))
        {
            System.out.println(prefixString);
            set.add(prefixString);
        }
    }
    else
    {
        for(int i=0; i<n; i++)
        {
            permute(prefixString + s.charAt(i), s.substring(0,i) + s.substring(i+1,n), set);
        }
    }
}
}
Paul92
источник
0
/*
     * eg: abc =>{a,bc},{b,ac},{c,ab}
     * =>{ca,b},{cb,a}
     * =>cba,cab
     * =>{ba,c},{bc,a}
     * =>bca,bac
     * =>{ab,c},{ac,b}
     * =>acb,abc
     */
    public void nonRecpermute(String prefix, String word)
    {
        String[] currentstr ={prefix,word};
        Stack<String[]> stack = new Stack<String[]>();
        stack.add(currentstr);
        while(!stack.isEmpty())
        {
            currentstr = stack.pop();
            String currentPrefix = currentstr[0];
            String currentWord = currentstr[1];
            if(currentWord.equals(""))
            {
                System.out.println("Word ="+currentPrefix);
            }
            for(int i=0;i<currentWord.length();i++)
            {
                String[] newstr = new String[2];
                newstr[0]=currentPrefix + String.valueOf(currentWord.charAt(i));
                newstr[1] = currentWord.substring(0, i);
                if(i<currentWord.length()-1)
                {
                    newstr[1] = newstr[1]+currentWord.substring(i+1);
                }
                stack.push(newstr);
            }

        }

    }
НЯЦ
источник
0

Это можно сделать итеративно, просто вставляя каждую букву строки по очереди во все места предыдущих частичных результатов.

Начнем с того [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"));

}
Трой Доусон
источник
0

Вот реализация Java:

/* All Permutations of a String */

import java.util.*;
import java.lang.*;
import java.io.*;

/* Complexity O(n*n!) */
class Ideone
{
     public static ArrayList<String> strPerm(String str, ArrayList<String> list)
     {
        int len = str.length();
        if(len==1){
            list.add(str);
            return list;
        }

        list = strPerm(str.substring(0,len-1),list);
        int ls = list.size();
        char ap = str.charAt(len-1);
        for(int i=0;i<ls;i++){
            String temp = list.get(i);
            int tl = temp.length();
            for(int j=0;j<=tl;j++){
                list.add(temp.substring(0,j)+ap+temp.substring(j,tl));  
            }
        }

        while(true){
            String temp = list.get(0);
            if(temp.length()<len)
                list.remove(temp);
            else
                break;
        }

        return list;
    }

    public static void main (String[] args) throws java.lang.Exception
    {
        String str = "abc";
        ArrayList<String> list = new ArrayList<>();

        list = strPerm(str,list);
        System.out.println("Total Permutations : "+list.size());
        for(int i=0;i<list.size();i++)
            System.out.println(list.get(i));

    }
}

http://ideone.com/nWPb3k

Сахил Чхабра
источник