特定の文字列のすべての順列を生成する


418

文字列のすべての順列を見つけるためのエレガントな方法は何ですか。たとえば、の順列はba、とですがbaabなどの長い文字列はabcdefghどうですか?Javaの実装例はありますか?


3
答えの多くはここにありますstackoverflow.com/questions/361/...
マレクSapota

これは非常に人気のある質問です。ここをご覧ください。careercup.com
question?

9
言及する必要がある仮定があります。キャラクターはユニークです。たとえば、文字列「aaaa」の場合、答えは1つだけです。より一般的な答えを得るには、文字列をセットに保存して重複を避けることができます
Afshin Moazami

1
文字の繰り返しは許可されていますか、それとも文字の繰り返しは許可されていませんか?1つの文字列に同じ文字が複数出現することはありますか?
アンダーソングリーン

2
理論を読んで(または、私のように怠惰な場合は、en.wikipedia.org/wiki/Permutationにアクセスして)、実際のアルゴリズムを実装してください。基本的に、要素の順序のシーケンスを生成し(文字列であるという事実は無関係です)、最初に戻るまで順序を確認できます。再帰や文字列操作を伴うものは避けてください。
CurtainDog 2014年

回答:


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プログラミング入門を介して)


67
ソリューションは、ここから来ているようですintrocs.cs.princeton.edu/java/23recursion/...
サイバー僧侶

48
それはロケット科学ではありません、私はほとんど同じ答えを思いつきました。微調整:まで再帰する代わりにn==0、でレベルを早く停止しn==1て印刷できprefix + strます。
lambshaanxy 2012年

7
「これの時間と空間の複雑さは何ですか?」並べ替えの質問に設定された結果は入力に対して階乗であるため、なんらかの部分的な回答のキャッシュがなければ、並べ替えを出力するアルゴリズムはo(n!)になります。
jeremyjjbrown 2013年

9
エレガントですね しかし、char配列に変換し、入れ替えて順列を生成するソリューションでは、コピーが大幅に減り、ガベージがはるかに少なくなります。また、このアルゴリズムは繰り返される文字を考慮に入れません。
Gene

20
@AfshinMoazami str.substring(i + 1、n)はstr.substring(i + 1)で置き換えることができると思います。str.substring(i)を使用すると、java.lang.StackOverflowErrorが発生します。
アユスマン2013

196

再帰を使用します。

  • 最初の文字として各文字を順番に試してから、再帰呼び出しを使用して残りの文字のすべての順列を見つけます。
  • 基本ケースは、入力が空の文字列の場合、唯一の順列は空の文字列です。

3
戻り値の型をpermuteメソッドに追加するにはどうすればよいですか?明らかにString型であっても、コンパイラーはこのメソッドの戻り型を反復ごとに判別できません。
user1712095 2014

この方法で異なる順列をどのように保証しますか?
kapad

70

これは、「Cracking the Coding Interview」(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]


Cracking the Coding Interview Book、6th Editionのページ(71)。:)
KarimIhab 2015年

5
これは本当に良い解決策ですか?結果をリストに格納することに依存しているため、短い入力文字列の場合、制御不能になります。
Androrider 2016年

マージは何をしますか?
Basavaraj Walikar、

これは、リスト内の各文字列のすべての可能な位置にあるC INSERTリストが含まれているので、もしのみ[「B」]、cがある「」マージ結果がある[「AB」、「BA」] と、ここで同じ溶液スウィフト gist.github。 com / daniaDlbani / 3bc10e02541f9ba310d546040c5322fc
Dania Delbani

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を使用するため、このスレッドの最初のソリューションよりもこのソリューションを優先します。私のソリューションが一時的な文字列を作成しないとは言えません(実際には、StringBufferが呼び出されるsystem.out.println場所で作成されますtoString())。しかし、これは、文字列リテラルが多すぎるという最初の解決策よりも優れていると感じています。「メモリ」の観点からこれを評価できるパフォーマンスの人がいるかもしれません(「時間」については、余分な「スワップ」のためにすでに遅れています)


理由だけでないif(index == str.length())doPerm(str, index + 1);?ここcurrPosは不要なようです。
Robur_131

申し訳ありませんが、質問について詳しく説明していただけますか?あなたが見てとることが示唆されていることを解決貼り付けてくださいされていない場合、あなただけの余分な変数currPosを使用しないように示唆されている(理由も複数発生すると可読性の使用)
スリカンスyaradla

ああ、私はあなたがフォワードインデックスを使ったベースコンディションの変化を意味していると思います。正常に動作します。私が提示したソリューションは、元のソリューションではなく切り捨てられた文字列を渡すことが多かった当時の他のソリューション(ほとんどの場合0は理にかなっています)の影響をほとんど受けました。それでも指摘してくれてありがとう。編集できるかどうか、このサイトにログインしてから数年になります。
srikanth yaradla

22

Javaの非常に基本的なソリューションは、ソリューション文字列を格納して返す場合、再帰+セット(繰り返しを避けるため)を使用することです。

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
このアルゴリズムの時間の複雑さは何ですか?
アシサフ2016

1
@ashisahu O(n!)nがあるので!長さnの指定された文字列の順列。
Zok

17

以前のすべての寄稿者は、コードの説明と提供について素晴らしい仕事をしてきました。誰かにも役立つかもしれないので、私もこのアプローチを共有する必要があると思いました。ソリューションは(ヒープのアルゴリズム)に基づいています

いくつかのこと:

  1. Excelに描かれている最後の項目は、ロジックをよりよく視覚化するのを助けるためのものであることに注意してください。したがって、最後の列の実際の値は2,1,0になります(配列を処理していて配列が0で始まるためにコードを実行した場合)。

  2. スワップアルゴリズムは、現在の位置の偶数または奇数の値に基づいて行われます。swapメソッドが呼び出されている場所を見ると、非常に自明です。何が起こっているのかを確認できます。

これが起こることです: ここに画像の説明を入力してください

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);
                }
            }
        }
    }

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;
}

この解決策は間違ってSystem.out.println(permute("AABBC").size());表示されているようです 45、実際には5!= 120
Mladen Adamovic 2016年

11

入力を使いましょう abc例としてを。

cセット(["c"])の最後の要素(b)から始めて、2番目の最後の要素()をその前、最後、および可能なすべての位置に["bc", "cb"]追加して、同じようにして次の要素を追加します後ろ(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文字未満の場合にのみ機能します。それ以外の場合、結果の配列の半分のみに一意の単語が含まれます。
マクシムマクシモフ2018

5

単純な解決策の1つは、2つのポインターを使用して再帰的に文字を交換し続けることです。

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!)
Nakul Kumar 2017

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','')

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);
        }
    }
}

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. リストのサイズが0または1の場合、空/リスト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;
}

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

階乗を使用して、特定の文字で始まる文字列の数を見つけることができます。

例:入力を取る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
    }
}

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]ます。

その背後にある基本的なロジックは

各文字について、それを最初の文字と見なし、残りの文字の組み合わせを見つけます。例えば[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) + "  ");
    }
}

それは何の説明が含まれていない、それはいくつかの他の回答と同じアルゴリズムを使用していますように私はこの答えは便利していない説明を提供します。
Bernhard Barker 14年

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;
    }
  }
}

入力str:1231

出力リスト:{1123、1132、1213、1231、1312、1321、2113、2131、2311、3112、3121、3211}

出力がソートされ、重複する結果がないことに注意してください。


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));
    }   
}

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);
        }
    }
}
}

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ます。

上記の製品では、1A2Bなどです。

ダーツのサンプル:

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.