주어진 문자열의 모든 순열 생성


418

문자열의 모든 순열을 찾는 우아한 방법은 무엇입니까? 예를 들어 ba,에 대한 순열은 baab같지만 더 긴 문자열은 abcdefgh무엇입니까? Java 구현 예제가 있습니까?


3
여기에 많은 답변이 있습니다 : stackoverflow.com/questions/361/…
Marek Sapota

이것은 매우 인기있는 질문입니다. 여기를보십시오 : careercup.com/question?id=3861299
JJunior

9
언급해야 할 가정이 있습니다. 캐릭터는 독특합니다. 예를 들어, 문자열 "aaaa"의 경우 한 가지 답변 만 있습니다. 보다 일반적인 대답을하려면 피할 중복에 일련의 문자열을 저장할 수 있습니다
아프신 Moazami

1
문자 반복이 허용됩니까, 아니면 문자 반복이 허용되지 않습니까? 단일 문자열에 동일한 문자가 여러 번 나타날 수 있습니까?
Anderson Green

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 프로그래밍 소개를 통해 )


67
해결책은 여기에서 오는 것 같습니다 introcs.cs.princeton.edu/java/23recursion/…
cyber-monk

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 메소드에 리턴 유형을 어떻게 추가 할 수 있습니까? 컴파일러는이 메소드의 리턴 유형을 문자열 유형 임에도 불구하고 모든 반복에서 판별 할 수 없습니다.
user1712095

이 방법에서 뚜렷한 순열을 어떻게 보장합니까?
kapad

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, 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]


코딩 면접 균열, 6 판의 페이지 (71). :)
KarimIhab

5
이것이 정말 좋은 해결책입니까? 결과를 목록에 저장하는 데 의존하므로 짧은 입력 문자열의 경우 제어 할 수 없습니다.
Androrider

병합은 무엇입니까?
Basavaraj Walikar 1

리스트에 각 문자열의 가능한 모든 위치에 c를 삽입하므로리스트에 [ "b"] 만 있고 c가 "a"인 경우 병합 결과는 [ "ab", "ba"] Swift gist.github
Dania Delbani

53

여기 및 다른 포럼에서 제공된 모든 솔루션 중에서 Mark Byers가 가장 마음에 들었습니다. 그 설명은 실제로 저 자신을 생각하고 코딩하게했습니다. 너무 나도 초보자이기 때문에 자신의 솔루션을 투표 할 수 없습니다.
어쨌든 여기에 그의 설명의 구현이 있습니다.

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를 사용하기 때문에이 스레드의 첫 번째 솔루션보다이 솔루션을 선호합니다. 내 솔루션이 임시 문자열을 만들지 않는다고 말하지는 않습니다 (실제로 of of 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
이 알고리즘의 시간 복잡성은 무엇입니까 ??
ashisahu

1
우리가 n을 가지고 있기 때문에 @ashisahu O (n!)! n 길이의 주어진 문자열에서 순열.
Zok

17

이전의 모든 기고자들은 코드를 설명하고 제공하는 훌륭한 일을했습니다. 나는 누군가에게 도움이 될 수 있기 때문에이 접근법을 공유해야한다고 생각했습니다. 솔루션은 ( 힙 알고리즘 )을 기반으로합니다.

몇 가지 :

  1. 엑셀에 표시된 마지막 항목은 로직을 더 잘 시각화하는 데 도움이되는 것입니다. 따라서 마지막 열의 실제 값은 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

11

입력을 사용하자 abc 을 예로 들어 .

c세트 ( ["c"]) 의 마지막 요소 ( )로 시작한 다음 두 번째 마지막 요소 ( b)를 앞쪽, 끝 및 중간의 가능한 모든 위치에 ["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 자 미만인 경우에만 작동하며, 그렇지 않으면 결과 배열의 절반에만 고유 단어가 포함됩니다.
Maksim Maksimov

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

5

파이썬 구현

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

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. 출력이 정렬됩니다

자바 코드는 다음과 같습니다.

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.

위의 제품에서 1is for A, 2is for 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

자바 구현은 다음과 같습니다.

/* 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.