문자열의 가능한 모든 순열 목록 생성


답변:


70

이를 수행하는 몇 가지 방법이 있습니다. 일반적인 방법은 재귀, 메모 또는 동적 프로그래밍을 사용합니다. 기본 아이디어는 길이가 1 인 모든 문자열의 목록을 생성 한 다음 각 반복에서 마지막 반복에서 생성 된 모든 문자열에 대해 문자열의 각 문자와 개별적으로 연결된 해당 문자열을 추가하는 것입니다. (아래 코드의 변수 인덱스는 마지막 반복의 시작과 다음 반복을 추적합니다)

일부 의사 코드 :

list = originalString.split('')
index = (0,0)
list = [""]
for iteration n in 1 to y:
  index = (index[1], len(list))
  for string s in list.subset(index[0] to end):
    for character c in originalString:
      list.add(s + c)

그런 다음 길이가 x보다 작은 모든 문자열을 제거해야합니다. 이는 목록에서 첫 번째 (x-1) * len (originalString) 항목입니다.


4
먼저 요소 목록을 저장 한 다음 지 웁니다. (의사 코드에서 라인 1과 3을 참조하십시오).
Håvard Geithus

6
y (4 행) 란 무엇입니까?
Jaseem

7
@Jaseem 질문에서 : " 길이 가 x와 y 사이 인 문자열의 모든 가능한 순열 "
ck_

39

역 추적을 사용하는 것이 좋습니다

#include <stdio.h>
#include <string.h>

void swap(char *a, char *b) {
    char temp;
    temp = *a;
    *a = *b;
    *b = temp;
}

void print(char *a, int i, int n) {
    int j;
    if(i == n) {
        printf("%s\n", a);
    } else {
        for(j = i; j <= n; j++) {
            swap(a + i, a + j);
            print(a, i + 1, n);
            swap(a + i, a + j);
        }
    }
}

int main(void) {
    char a[100];
    gets(a);
    print(a, 0, strlen(a) - 1);
    return 0;
}

3
최고의 솔루션 everrrrrrrrr
GrowinMan

25

당신은 많은 문자열을 얻을 것입니다, 그것은 확실합니다 ...

\ sum_ {i = x} ^ y {\ frac {r!} {{(ri)}!}}
여기서 x와 y는 그것들을 정의하는 방법이고 r은 우리가 선택하는 문자의 수입니다. 필요에 따라 이것을 생성하고 느슨해지지 말고 파워 세트를 생성 한 다음 문자열 길이를 필터링해야합니다.

다음은 이것들을 생성하는 가장 좋은 방법은 아니지만, 그럼에도 불구하고 흥미 롭습니다.

Knuth (volume 4, fascicle 2, 7.2.1.3)에 따르면 (s, t) 조합은 반복 할 때 한 번에 s + 1을 취한 것과 동일하다는 것을 알려줍니다. (s, t) 조합은 Knuth와 같습니다 {t \ 선택 {s + t}. 먼저 이진 형식 (길이 (s + t))으로 각 (s, t) 조합을 생성하고 각 1의 왼쪽에있는 0의 수를 세어이를 알아낼 수 있습니다.

10001000011101->는 순열이됩니다 : {0, 3, 4, 4, 4, 1}


15

Python의 Knuth에 따른 비 재귀 솔루션 :

def nextPermutation(perm):
    k0 = None
    for i in range(len(perm)-1):
        if perm[i]<perm[i+1]:
            k0=i
    if k0 == None:
        return None

    l0 = k0+1
    for i in range(k0+1, len(perm)):
        if perm[k0] < perm[i]:
            l0 = i

    perm[k0], perm[l0] = perm[l0], perm[k0]
    perm[k0+1:] = reversed(perm[k0+1:])
    return perm

perm=list("12345")
while perm:
    print perm
    perm = nextPermutation(perm)

2
실제로 문자열을 정렬 하지 않으면 작동 하지 않습니다 . 하나의 문자열 "54321"로만 시도하면 (자체) 표시됩니다.
tonjo

1
흥미로운 점 nextPermutation()은 상태 비 저장입니다. 순열을 위해 입력 만 받고 인덱스는 반복에서 반복으로 유지되지 않습니다. 초기 입력이 정렬되었다고 가정 하고 순서가 유지되는 위치에 따라 색인 ( k0l0) 자체를 찾아서 수행 할 수 있습니다. "54321"-> "12345"와 같은 입력을 정렬하면이 알고리즘이 예상되는 모든 순열을 찾을 수 있습니다. 그러나 생성되는 모든 순열에 대해 해당 인덱스를 다시 찾기 위해 많은 양의 추가 작업이 수행되므로 비재 귀적으로이를 수행하는보다 효율적인 방법이 있습니다.
spaaarky21 년

13

원하는 세트의 일부를 수행하는 알고리즘을 설명하는 " 세트의 서브 세트를 효율적으로 열거 "를 볼 수 있습니다 . 길이 x에서 y까지 N 문자의 모든 서브 세트를 신속하게 생성합니다. C로 구현되어 있습니다.

각 부분 집합에 대해 여전히 모든 순열을 생성해야합니다. 예를 들어 "abcde"에서 3자를 원하면이 알고리즘은 "abc", "abd", "abe"를 제공하지만 "acb", "bac", "bca"등


13

Sarp의 답변을 기반으로 작동하는 일부 Java 코드 :

public class permute {

    static void permute(int level, String permuted,
                    boolean used[], String original) {
        int length = original.length();
        if (level == length) {
            System.out.println(permuted);
        } else {
            for (int i = 0; i < length; i++) {
                if (!used[i]) {
                    used[i] = true;
                    permute(level + 1, permuted + original.charAt(i),
                       used, original);
                    used[i] = false;
                }
            }
        }
    }

    public static void main(String[] args) {
        String s = "hello";
        boolean used[] = {false, false, false, false, false};
        permute(0, "", used, s);
    }
}

주석으로, 반복되는 문자가있는 문자열의 경우 고유 순열이 생성되지 않습니다. 이것은 해시로 해결할 수 있지만 긴 문자열에는 문제가 될 수 있습니다.
Glenn

8
문자열은 java에서 변경할 수 없으므로 문자열 대신 char 배열을 사용하여 더 빠르게 실행할 수 있습니다.
Abhijeet Kashnia

13

다음은 C #의 간단한 솔루션입니다.

주어진 문자열의 고유 한 순열 만 생성합니다.

    static public IEnumerable<string> permute(string word)
    {
        if (word.Length > 1)
        {

            char character = word[0];
            foreach (string subPermute in permute(word.Substring(1)))
            {

                for (int index = 0; index <= subPermute.Length; index++)
                {
                    string pre = subPermute.Substring(0, index);
                    string post = subPermute.Substring(index);

                    if (post.Contains(character))
                            continue;                       

                    yield return pre + character + post;
                }

            }
        }
        else
        {
            yield return word;
        }
    }

12

여기에 좋은 답변이 많이 있습니다. 또한 C ++에서 매우 간단한 재귀 솔루션을 제안합니다.

#include <string>
#include <iostream>

template<typename Consume>
void permutations(std::string s, Consume consume, std::size_t start = 0) {
    if (start == s.length()) consume(s);
    for (std::size_t i = start; i < s.length(); i++) {
        std::swap(s[start], s[i]);
        permutations(s, consume, start + 1);
    }
}

int main(void) {
    std::string s = "abcd";
    permutations(s, [](std::string s) {
        std::cout << s << std::endl;
    });
}

참고 : 문자가 반복되는 문자열은 고유 한 순열을 생성하지 않습니다.


9

방금 Ruby에서 이것을 빨리 채웠습니다.

def perms(x, y, possible_characters)
  all = [""]
  current_array = all.clone
  1.upto(y) { |iteration|
    next_array = []
    current_array.each { |string|
      possible_characters.each { |c|
        value = string + c
        next_array.insert next_array.length, value
        all.insert all.length, value
      }
    }
    current_array = next_array
  }
  all.delete_if { |string| string.length < x }
end

내장 순열 유형 함수에 대해 언어 API를 살펴보고 더 최적화 된 코드를 작성할 수 있지만 숫자가 모두 높으면 많은 결과를 얻을 수있는 방법이 많지 않습니다. .

어쨌든 코드 뒤의 아이디어는 길이가 0 인 문자열로 시작한 다음 길이가 Z 인 모든 문자열을 추적합니다. 여기서 Z는 반복의 현재 크기입니다. 그런 다음 각 문자열을 살펴보고 각 문자열에 각 문자를 추가하십시오. 마지막으로 x 임계 값 미만인 것을 제거하고 결과를 반환합니다.

잠재적으로 의미가없는 입력 (널 문자 목록, x 및 y의 이상한 값 등)으로 테스트하지 않았습니다.


11
이 코드는 잘못되었습니다. 문자가 반복되는 것과 같은 잘못된 순열을 생성합니다. 예를 들어 문자열 "abc"의 경우 크기 3의 이러한 순열을 생성합니다. [ "aaa", "aab", "aac", "aba", "abb", "abc", "aca", "acb", "acc", "baa", "bab", "bac", "bba", "bbb", "bbc", "bca", "bcb", "bcc", "caa", "cab", "cac ","cba ","cbb ","cbc ","cca ","ccb ","ccc "]. 이것은 올바르지 않습니다.
pmc255

8

이것은 Mike의 Ruby 버전을 Common Lisp로 번역 한 것입니다.

(defun perms (x y original-string)
  (loop with all = (list "")
        with current-array = (list "")
        for iteration from 1 to y
        do (loop with next-array = nil
                 for string in current-array
                 do (loop for c across original-string
                          for value = (concatenate 'string string (string c))
                          do (push value next-array)
                             (push value all))
                    (setf current-array (reverse next-array)))
        finally (return (nreverse (delete-if #'(lambda (el) (< (length el) x)) all)))))

또 다른 버전은 약간 짧고 더 많은 루프 기능을 사용합니다.

(defun perms (x y original-string)
  (loop repeat y
        collect (loop for string in (or (car (last sets)) (list ""))
                      append (loop for c across original-string
                                   collect (concatenate 'string string (string c)))) into sets
        finally (return (loop for set in sets
                              append (loop for el in set when (>= (length el) x) collect el)))))

8

간단한 단어 C # 재귀 솔루션은 다음과 같습니다.

방법:

public ArrayList CalculateWordPermutations(string[] letters, ArrayList words, int index)
        {
            bool finished = true;
            ArrayList newWords = new ArrayList();
            if (words.Count == 0)
            {
                foreach (string letter in letters)
                {
                    words.Add(letter);
                }
            }

            for(int j=index; j<words.Count; j++)
            {
                string word = (string)words[j];
                for(int i =0; i<letters.Length; i++)
                {
                    if(!word.Contains(letters[i]))
                    {
                        finished = false;
                        string newWord = (string)word.Clone();
                        newWord += letters[i];
                        newWords.Add(newWord);
                    }
                }
            }

            foreach (string newWord in newWords)
            {   
                words.Add(newWord);
            }

            if(finished  == false)
            {
                CalculateWordPermutations(letters, words, words.Count - newWords.Count);
            }
            return words;
        }

부름:

string[] letters = new string[]{"a","b","c"};
ArrayList words = CalculateWordPermutations(letters, new ArrayList(), 0);

8

... 그리고 여기에 C 버전이 있습니다 :

void permute(const char *s, char *out, int *used, int len, int lev)
{
    if (len == lev) {
        out[lev] = '\0';
        puts(out);
        return;
    }

    int i;
    for (i = 0; i < len; ++i) {
        if (! used[i])
            continue;

        used[i] = 1;
        out[lev] = s[i];
        permute(s, out, used, len, lev + 1);
        used[i] = 0;
    }
    return;
}

8

순열 (ABC)-> A.perm (BC)-> A.perm [B.perm (C)]-> A.perm [( * B C), (C B * )]-> [( * A BC ), (B A C), (BC A * ), ( * A CB), (C A B), (CB A * )] 각 알파벳을 삽입 할 때 중복을 제거하려면 이전 문자열이 동일한 알파벳으로 끝나는 지 확인하십시오 (왜?-운동)

public static void main(String[] args) {

    for (String str : permStr("ABBB")){
        System.out.println(str);
    }
}

static Vector<String> permStr(String str){

    if (str.length() == 1){
        Vector<String> ret = new Vector<String>();
        ret.add(str);
        return ret;
    }

    char start = str.charAt(0);
    Vector<String> endStrs = permStr(str.substring(1));
    Vector<String> newEndStrs = new Vector<String>();
    for (String endStr : endStrs){
        for (int j = 0; j <= endStr.length(); j++){
            if (endStr.substring(0, j).endsWith(String.valueOf(start)))
                break;
            newEndStrs.add(endStr.substring(0, j) + String.valueOf(start) + endStr.substring(j));
        }
    }
    return newEndStrs;
}

모든 순열 산술 중복을 인쇄합니다


8

C ++의 재귀 솔루션

int main (int argc, char * const argv[]) {
        string s = "sarp";
        bool used [4];
        permute(0, "", used, s);
}

void permute(int level, string permuted, bool used [], string &original) {
    int length = original.length();

    if(level == length) { // permutation complete, display
        cout << permuted << endl;
    } else {
        for(int i=0; i<length; i++) { // try to add an unused character
            if(!used[i]) {
                used[i] = true;
                permute(level+1, original[i] + permuted, used, original); // find the permutations starting with this string
                used[i] = false;
            }
        }
}

7

Perl에서 소문자 알파벳으로 자신을 제한하려면 다음을 수행하십시오.

my @result = ("a" .. "zzzz");

소문자를 사용하여 1 ~ 4 자 사이의 모든 가능한 문자열을 제공합니다. 대문자 변경의 경우 "a""A""zzzz""ZZZZ".

대소 문자를 혼합하면 훨씬 어려워지고 아마도 Perl의 내장 연산자 중 하나에서는 불가능할 것입니다.


7

작동하는 루비 답변 :

class String
  def each_char_with_index
    0.upto(size - 1) do |index|
      yield(self[index..index], index)
    end
  end
  def remove_char_at(index)
    return self[1..-1] if index == 0
    self[0..(index-1)] + self[(index+1)..-1]
  end
end

def permute(str, prefix = '')
  if str.size == 0
    puts prefix
    return
  end
  str.each_char_with_index do |char, index|
    permute(str.remove_char_at(index), prefix + char)
  end
end

# example
# permute("abc")

Ruby의 멋진 하나의 라이너 : stackoverflow.com/questions/5773961/…
dojosto

6
import java.util.*;

public class all_subsets {
    public static void main(String[] args) {
        String a = "abcd";
        for(String s: all_perm(a)) {
            System.out.println(s);
        }
    }

    public static Set<String> concat(String c, Set<String> lst) {
        HashSet<String> ret_set = new HashSet<String>();
        for(String s: lst) {
            ret_set.add(c+s);
        }
        return ret_set;
    }

    public static HashSet<String> all_perm(String a) {
        HashSet<String> set = new HashSet<String>();
        if(a.length() == 1) {
            set.add(a);
        } else {
            for(int i=0; i<a.length(); i++) {
                set.addAll(concat(a.charAt(i)+"", all_perm(a.substring(0, i)+a.substring(i+1, a.length()))));
            }
        }
        return set;
    }
}

6

다음 Java 재귀는 주어진 문자열의 모든 순열을 인쇄합니다.

//call it as permut("",str);

public void permut(String str1,String str2){
    if(str2.length() != 0){
        char ch = str2.charAt(0);
        for(int i = 0; i <= str1.length();i++)
            permut(str1.substring(0,i) + ch + str1.substring(i,str1.length()),
                     str2.substring(1,str2.length()));
    }else{
    System.out.println(str1);
    }
}

다음은 n을 만드는 위의 "permut"메소드의 업데이트 된 버전입니다! 위의 방법과 비교하여 (n factorial) 덜 재귀 호출

//call it as permut("",str);

public void permut(String str1,String str2){
   if(str2.length() > 1){
       char ch = str2.charAt(0);
       for(int i = 0; i <= str1.length();i++)
          permut(str1.substring(0,i) + ch + str1.substring(i,str1.length()),
                 str2.substring(1,str2.length()));
   }else{
    char ch = str2.charAt(0);
    for(int i = 0; i <= str1.length();i++)
        System.out.println(str1.substring(0,i) + ch +    str1.substring(i,str1.length()),
                 str2.substring(1,str2.length()));
   }
}

이것은 가장 깨끗한 해결책이며, 나는 "코딩 인터뷰 균열"책에서 전에 본 적이 있다고 생각합니다.
Tao Zhang

1
@TaoZhang의 보완에 감사드립니다. 어디에서나 복사하지 않았지만 비슷한 알고리즘을 만들었을 수도 있습니다. 어쨌든 나는 덜 재귀 호출을 위해 위의 코드를 업데이트했습니다
Ramy

5

왜 당신이 처음에 이것을하고 싶은지 잘 모르겠습니다. 적당히 큰 x 및 y 값에 대한 결과 집합은 크며 x 및 / 또는 y가 커짐에 따라 기하 급수적으로 증가합니다.

가능한 문자 집합은 알파벳의 소문자 26 자이며 응용 프로그램에 길이 = 5 인 모든 순열을 생성하도록 요청합니다. 메모리가 부족하지 않다고 가정하면 11,881,376이됩니다 (즉, 26의 거듭 제곱 5) 다시 문자열. 그 길이를 최대 6까지 범프하면 308,915,776 개의 문자열이 다시 나타납니다. 이 숫자는 고통스럽게 커지고 매우 빠릅니다.

다음은 Java로 통합 한 솔루션입니다. x와 y에 해당하는 두 개의 런타임 인수를 제공해야합니다. 즐기세요

public class GeneratePermutations {
    public static void main(String[] args) {
        int lower = Integer.parseInt(args[0]);
        int upper = Integer.parseInt(args[1]);

        if (upper < lower || upper == 0 || lower == 0) {
            System.exit(0);
        }

        for (int length = lower; length <= upper; length++) {
            generate(length, "");
        }
    }

    private static void generate(int length, String partial) {
        if (length <= 0) {
            System.out.println(partial);
        } else {
            for (char c = 'a'; c <= 'z'; c++) {
                generate(length - 1, partial + c);
            }
        }
    }
}

오랜 시간이지만 반복하여 생성하지 않습니까?
카키 라

5

여기에 자바 스크립트에서 비 재귀 버전이 있습니다. 위의 Knuth의 비재 귀적 인 것을 기반으로하지는 않지만 요소 교환과 약간의 유사성이 있습니다. 최대 8 개 요소의 입력 배열에 대한 정확성을 확인했습니다.

빠른 최적화는 out어레이를 사전 비행 하고 피하는 것 push()입니다.

기본 아이디어는 다음과 같습니다.

  1. 단일 소스 배열이 주어지면, 첫 번째 요소를 각 후속 요소와 차례로 바꾸는 새로운 배열 세트를 생성하십시오. 예 : 1234로 1234, 2134, 3214, 4231을 생성하십시오.

  2. 이전 패스의 각 배열을 새 패스의 시드로 사용하지만 첫 번째 요소를 바꾸는 대신 두 번째 요소를 각 후속 요소와 바꾸십시오. 또한 이번에는 원본 배열을 출력에 포함시키지 마십시오.

  3. 완료 될 때까지 2 단계를 반복하십시오.

코드 샘플은 다음과 같습니다.

function oxe_perm(src, depth, index)
{
    var perm = src.slice();     // duplicates src.
    perm = perm.split("");
    perm[depth] = src[index];
    perm[index] = src[depth];
    perm = perm.join("");
    return perm;
}

function oxe_permutations(src)
{
    out = new Array();

    out.push(src);

    for (depth = 0; depth < src.length; depth++) {
        var numInPreviousPass = out.length;
        for (var m = 0; m < numInPreviousPass; ++m) {
            for (var n = depth + 1; n < src.length; ++n) {
                out.push(oxe_perm(out[m], depth, n));
            }
        }
    }

    return out;
}

3

루비에서 :

str = "a"
100_000_000.times {puts str.next!}

꽤 빠르지 만 시간이 걸릴 것입니다 =). 물론 짧은 줄이 흥미롭지 않으면 "aaaaaaaa"에서 시작할 수 있습니다.

실제 질문을 잘못 해석했을 수도 있습니다. 포스트 중 하나에서 마치 무차별 문자열 라이브러리가 필요한 것처럼 들리지만 주요 질문에서는 특정 문자열을 치환 해야하는 것처럼 들립니다.

귀하의 문제는 다음과 비슷합니다 : http://beust.com/weblog/archives/000491.html (숫자가 자체적으로 반복되지 않는 모든 정수를 나열하십시오. 순열을 사용하는 ocaml guy, 또 다른 솔루션을 사용하는 일부 java guy).


귀하의 제안과 관련된 문제는 str.next입니다! 인쇄 가능한 모든 문자를 반복하지는 않습니다. 이 예에서는 구두점이 없거나 대문자 인 소문자 만 생성합니다.
Jarsen

3

나는 오늘 이것을 필요로했고, 이미 주어진 대답이 나를 올바른 방향으로 지적했지만, 그들은 내가 원하는 것이 아니었다.

다음은 Heap의 방법을 사용한 구현입니다. 어레이의 길이는 3 이상이어야하며 실제 고려 사항은 수행하려는 작업, 인내 및 클럭 속도에 따라 10 이상이 아니어야합니다.

당신은 당신의 루프 초기화를 입력하기 전에 Perm(1 To N)첫 번째 순열과 Stack(3 To N)제로는, 그리고 *와 Level함께 2**을. 루프 호출의 끝에서 NextPerm완료되면 false를 반환합니다.

* VB가 당신을 위해 그렇게 할 것입니다.

** NextPerm을 약간 변경하여이를 불필요하게 만들 수 있지만 이와 같이 더 명확합니다.

Option Explicit

Function NextPerm(Perm() As Long, Stack() As Long, Level As Long) As Boolean
Dim N As Long
If Level = 2 Then
    Swap Perm(1), Perm(2)
    Level = 3
Else
    While Stack(Level) = Level - 1
        Stack(Level) = 0
        If Level = UBound(Stack) Then Exit Function
        Level = Level + 1
    Wend
    Stack(Level) = Stack(Level) + 1
    If Level And 1 Then N = 1 Else N = Stack(Level)
    Swap Perm(N), Perm(Level)
    Level = 2
End If
NextPerm = True
End Function

Sub Swap(A As Long, B As Long)
A = A Xor B
B = A Xor B
A = A Xor B
End Sub

'This is just for testing.
Private Sub Form_Paint()
Const Max = 8
Dim A(1 To Max) As Long, I As Long
Dim S(3 To Max) As Long, J As Long
Dim Test As New Collection, T As String
For I = 1 To UBound(A)
    A(I) = I
Next
Cls
ScaleLeft = 0
J = 2
Do
    If CurrentY + TextHeight("0") > ScaleHeight Then
        ScaleLeft = ScaleLeft - TextWidth(" 0 ") * (UBound(A) + 1)
        CurrentY = 0
        CurrentX = 0
    End If
    T = vbNullString
    For I = 1 To UBound(A)
        Print A(I);
        T = T & Hex(A(I))
    Next
    Print
    Test.Add Null, T
Loop While NextPerm(A, S, J)
J = 1
For I = 2 To UBound(A)
    J = J * I
Next
If J <> Test.Count Then Stop
End Sub

다른 방법은 다양한 저자가 설명합니다. Knuth는 두 가지를 설명하는데, 하나는 어휘 순서를 제공하지만 복잡하고 느리고 다른 하나는 일반 변경 방법으로 알려져 있습니다. Jie Gao와 Dianjun Wang도 흥미로운 논문을 썼습니다.


2

파이썬 에서이 코드는 최대 4 자로 allowed_characters설정하면 [0,1]2 ^ 4 결과를 생성합니다.

['0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111']

def generate_permutations(chars = 4) :

#modify if in need!
    allowed_chars = [
        '0',
        '1',
    ]

    status = []
    for tmp in range(chars) :
        status.append(0)

    last_char = len(allowed_chars)

    rows = []
    for x in xrange(last_char ** chars) :
        rows.append("")
        for y in range(chars - 1 , -1, -1) :
            key = status[y]
            rows[x] = allowed_chars[key] + rows[x]

        for pos in range(chars - 1, -1, -1) :
            if(status[pos] == last_char - 1) :
                status[pos] = 0
            else :
                status[pos] += 1
                break;

    return rows

import sys


print generate_permutations()

이것이 당신에게 사용되기를 바랍니다. 숫자뿐만 아니라 모든 문자와 작동


이것은 순열이 아니라 부분 집합 선택입니다. 예를 들어 ABC & 001 = C이지만 유효한 순열에는 세 개의 문자가 모두 있어야합니다.
Schultz9999

어? 죄송합니다 당신이 무슨 말을 이해하지 못합니다. 고정 버전을 남겨두면 문제를 커뮤니티 위키로 만들 것입니다.
droope


0

이것이 귀하의 질문에 정확하게 대답하지는 않지만, 동일한 길이의 여러 문자열에서 문자의 모든 순열을 생성하는 한 가지 방법이 있습니다. 예를 들어, 단어가 "커피", "joomla"및 "무들"인 경우 "coodle", "joodee", "joffle"등과 같은 출력을 기대하십시오.

기본적으로 조합 수는 (단어 수)에서 (단어 당 문자 수)의 제곱입니다. 따라서 0과 조합 수-1 사이의 임의의 숫자를 선택하고 해당 숫자를 기본 (단어 수)으로 변환 한 다음 해당 숫자의 각 숫자를 다음 문자를 가져올 단어의 표시기로 사용하십시오.

예 : 위의 예에서. 3 단어, 6 글자 = 729 조합. 난수를 선택하십시오. 465. 밑줄 3으로 전환하십시오 : 122020. 단어 1에서 첫 번째 문자, 단어 2에서 두 번째, 단어 2에서 세 번째, 단어 0에서 네 번째 ...를 받으면 "joofle"이됩니다.

모든 순열을 원한다면 0에서 728까지 반복하십시오. 물론 하나의 임의의 값을 선택 하는 경우 문자를 반복하는 것이 훨씬 간단 합니다. 이 방법을 사용하면 모든 순열을 원할 때 재귀를 피할 수 있으며 수학 (tm) 을 아는 것처럼 보일 수 있습니다 !

조합 수가 너무 많으면 일련의 작은 단어로 분리하여 마지막에 연결할 수 있습니다.


0

C # 반복 :

public List<string> Permutations(char[] chars)
    {
        List<string> words = new List<string>();
        words.Add(chars[0].ToString());
        for (int i = 1; i < chars.Length; ++i)
        {
            int currLen = words.Count;
            for (int j = 0; j < currLen; ++j)
            {
                var w = words[j];
                for (int k = 0; k <= w.Length; ++k)
                {
                    var nstr = w.Insert(k, chars[i].ToString());
                    if (k == 0)
                        words[j] = nstr;
                    else
                        words.Add(nstr);
                }
            }
        }
        return words;
    }

0
def gen( x,y,list): #to generate all strings inserting y at different positions
list = []
list.append( y+x )
for i in range( len(x) ):
    list.append( func(x,0,i) + y + func(x,i+1,len(x)-1) )
return list 

def func( x,i,j ): #returns x[i..j]
z = '' 
for i in range(i,j+1):
    z = z+x[i]
return z 

def perm( x , length , list ): #perm function
if length == 1 : # base case
    list.append( x[len(x)-1] )
    return list 
else:
    lists = perm( x , length-1 ,list )
    lists_temp = lists #temporarily storing the list 
    lists = []
    for i in range( len(lists_temp) ) :
        list_temp = gen(lists_temp[i],x[length-2],lists)
        lists += list_temp 
    return lists

0
def permutation(str)
  posibilities = []
  str.split('').each do |char|
    if posibilities.size == 0
      posibilities[0] = char.downcase
      posibilities[1] = char.upcase
    else
      posibilities_count = posibilities.length
      posibilities = posibilities + posibilities
      posibilities_count.times do |i|
        posibilities[i] += char.downcase
        posibilities[i+posibilities_count] += char.upcase
      end
    end
  end
  posibilities
end

비 재귀 버전에 대한 설명입니다.


0

파이 토닉 솔루션 :

from itertools import permutations
s = 'ABCDEF'
p = [''.join(x) for x in permutations(s)]

0

여기에 우아하고 비 재귀적인 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;
    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.