Tạo danh sách tất cả các hoán vị có thể có của một chuỗi


Câu trả lời:


70

Có nhiều hướng khác nhau để làm điều đó. Các phương pháp phổ biến sử dụng đệ quy, ghi nhớ hoặc lập trình động. Ý tưởng cơ bản là bạn tạo ra một danh sách tất cả các chuỗi có độ dài 1, sau đó trong mỗi lần lặp, cho tất cả các chuỗi được tạo trong lần lặp cuối cùng, hãy thêm chuỗi đó được nối với từng ký tự trong chuỗi riêng lẻ. (chỉ số biến trong mã bên dưới theo dõi sự bắt đầu của lần lặp cuối cùng và lần lặp tiếp theo)

Một số mã giả:

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)

Sau đó, bạn cần xóa tất cả các chuỗi có độ dài nhỏ hơn x, chúng sẽ là mục nhập đầu tiên (x-1) * len (originalString) trong danh sách.


4
Tại sao đầu tiên lưu trữ danh sách các yếu tố, và sau đó xóa nó? (đề cập đến dòng 1 và 3 trong mã giả).
Håvard Geithus

6
Y (dòng 4) là gì?
Jaseem

7
@Jaseem Từ câu hỏi: "tất cả các hoán vị có thể có của một chuỗi giữa các ký tự x và y "
ck_

39

Tốt hơn hết là sử dụng quay lui

#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
Giải pháp tốt nhất everrrrrrrrr
GrowinMan 11/03/2015

25

Bạn sẽ nhận được rất nhiều chuỗi, chắc chắn ...

\ sum_ {i = x} ^ y {\ frac {r!} {{(ri)}!}}
Trong đó x và y là cách bạn xác định chúng và r là số lượng ký tự chúng tôi đang chọn từ - nếu tôi hiểu bạn chính xác. Bạn chắc chắn nên tạo ra những thứ này khi cần thiết và không bị cẩu thả và nói, tạo một bộ quyền hạn và sau đó lọc độ dài của chuỗi.

Sau đây chắc chắn không phải là cách tốt nhất để tạo ra những thứ này, nhưng đó là một điều thú vị, không hơn không kém.

Knuth (tập 4, fascicle 2, 7.2.1.3) cho chúng ta biết rằng tổ chức (s, t) tương đương với s + 1 thứ được thực hiện tại một thời điểm với sự lặp lại - một tổ chức (s, t) là ký hiệu được sử dụng bởi Knuth đó là bằng {t \ chọn {s + t}. Chúng ta có thể tìm ra điều này bằng cách trước tiên tạo ra từng tổ chức (s, t) ở dạng nhị phân (vì vậy, độ dài (s + t)) và đếm số 0 ở bên trái của mỗi 1.

10001000011101 -> trở thành hoán vị: {0, 3, 4, 4, 4, 1}


15

Giải pháp không đệ quy theo Knuth, ví dụ Python:

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
Trên thực tế, điều này không hoạt động khi chuỗi không được sắp xếp. Nếu bạn thử "54321"chỉ với MỘT chuỗi được hiển thị (chính nó).
tonjo

1
Điều thú vị là nextPermutation()không trạng thái - chỉ mất đầu vào để hoán vị và các chỉ mục không được duy trì từ lần lặp đến lần lặp. Có thể làm như vậy bằng cách giả sử rằng đầu vào ban đầu đã được sắp xếp và tự tìm chỉ mục ( k0l0), dựa trên nơi duy trì thứ tự. Sắp xếp một đầu vào như "54321" -> "12345" sẽ cho phép thuật toán này tìm thấy tất cả các hoán vị dự kiến. Nhưng vì nó thực hiện rất nhiều công việc bổ sung để tìm lại các chỉ mục đó cho mỗi hoán vị mà nó tạo ra, có nhiều cách hiệu quả hơn để thực hiện việc này không đệ quy.
spaaarky21

13

Bạn có thể xem " Liệt kê hiệu quả các tập hợp con của tập hợp ", mô tả thuật toán để thực hiện một phần những gì bạn muốn - nhanh chóng tạo ra tất cả các tập hợp con của N ký tự từ độ dài x đến y. Nó chứa một triển khai trong C.

Đối với mỗi tập hợp con, bạn vẫn phải tạo tất cả các hoán vị. Chẳng hạn, nếu bạn muốn có 3 ký tự từ "abcde", thuật toán này sẽ cung cấp cho bạn "abc", "abd", "abe" ... nhưng bạn phải hoán vị từng ký tự để có được "acb", "bac", "Bca", v.v.


13

Một số mã Java hoạt động dựa trên câu trả lời của Sarp :

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

Như một nhận xét, lưu ý rằng đối với một chuỗi có các ký tự lặp lại, điều này sẽ không tạo ra các hoán vị duy nhất. Điều này có thể được giải quyết bằng hàm băm, nhưng đó có thể là một vấn đề với chuỗi dài.
Glenn

8
Bạn có thể muốn sử dụng các mảng char thay vì các chuỗi để làm cho việc này chạy nhanh hơn vì các chuỗi là bất biến trong java.
Abhijeet Kashnia

13

Đây là một giải pháp đơn giản trong C #.

Nó chỉ tạo ra các hoán vị riêng biệt của một chuỗi nhất định.

    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ó rất nhiều câu trả lời tốt ở đây. Tôi cũng đề xuất một giải pháp đệ quy rất đơn giản trong 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;
    });
}

Lưu ý : chuỗi có ký tự lặp lại sẽ không tạo ra hoán vị duy nhất.


9

Tôi vừa đánh nó nhanh lên trong 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

Bạn có thể xem xét API ngôn ngữ để xây dựng các hàm loại hoán vị và bạn có thể viết mã được tối ưu hóa hơn, nhưng nếu các con số quá cao, tôi không chắc có nhiều cách để có nhiều kết quả .

Dù sao, ý tưởng đằng sau mã được bắt đầu bằng chuỗi có độ dài 0, sau đó theo dõi tất cả các chuỗi có độ dài Z trong đó Z là kích thước hiện tại trong lần lặp. Sau đó, đi qua từng chuỗi và nối từng ký tự vào từng chuỗi. Cuối cùng ở cuối, loại bỏ bất kỳ cái nào dưới ngưỡng x và trả về kết quả.

Tôi đã không kiểm tra nó với đầu vào vô nghĩa (danh sách ký tự null, giá trị lạ của x và y, v.v.).


11
Mã này là SAI. Nó sẽ tạo ra các hoán vị không hợp lệ, chẳng hạn như các ký tự lặp lại. Ví dụ: đối với chuỗi "abc", nó tạo ra các hoán vị có kích thước 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 "]. Điều này là không đúng.
pmc255

8

Đây là bản dịch của phiên bản Ruby của Mike, sang 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)))))

Và một phiên bản khác, ngắn hơn một chút và sử dụng nhiều tính năng cơ sở vòng lặp hơn:

(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

Đây là một từ đơn giản giải pháp đệ quy C #:

Phương pháp:

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

Gọi điện thoại:

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

8

... và đây là phiên bản 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

hoán vị (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 * )] Để xóa trùng lặp khi chèn từng kiểm tra bảng chữ cái để xem chuỗi trước kết thúc với cùng một bảng chữ cái (tại sao? -xuất hiện)

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

In tất cả các hoán vị sans trùng lặp


8

Giải pháp đệ quy trong 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

Trong Perl, nếu bạn muốn giới hạn bản thân trong bảng chữ cái chữ thường, bạn có thể làm điều này:

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

Điều này cung cấp cho tất cả các chuỗi có thể có từ 1 đến 4 ký tự bằng cách sử dụng các ký tự chữ thường. Đối với chữ hoa, thay đổi "a"thành "A""zzzz"sang "ZZZZ".

Đối với trường hợp hỗn hợp, việc này trở nên khó khăn hơn nhiều và có lẽ không thể thực hiện được với một trong những toán tử dựng sẵn của Perl như thế.


7

Ruby trả lời có tác dụng:

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")

Đối với một lớp lót ưa thích trong Ruby: stackoverflow.com/questions/5773961/ từ
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

Đệ quy Java sau đây in tất cả các hoán vị của một chuỗi đã cho:

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

Sau đây là phiên bản cập nhật của phương pháp "permut" ở trên, làm cho n! (n factorial) các cuộc gọi đệ quy ít hơn so với phương thức trên

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

Đây là giải pháp sạch nhất và tôi tin rằng tôi đã thấy nó trước đây trong cuốn sách "Bẻ khóa phỏng vấn mã hóa"
Tao Zhang

1
@TaoZhang cảm ơn vì sự bổ sung, tôi đã không sao chép nó từ bất cứ đâu tuy nhiên có thể ai đó đã tạo ra thuật toán tương tự. Dù sao, tôi đã cập nhật mã ở trên cho các cuộc gọi đệ quy ít hơn
Ramy

5

Tôi không chắc tại sao bạn lại muốn làm điều này ngay từ đầu. Tập kết quả cho bất kỳ giá trị lớn vừa phải của x và y sẽ rất lớn và sẽ tăng theo cấp số nhân khi x và / hoặc y lớn hơn.

Giả sử tập hợp các ký tự có thể của bạn là 26 chữ cái viết thường của bảng chữ cái và bạn yêu cầu ứng dụng của mình tạo ra tất cả các hoán vị trong đó length = 5. Giả sử bạn không hết bộ nhớ, bạn sẽ nhận được 11.881.376 (tức là 26 cho sức mạnh của 5) chuỗi trở lại. Bump có độ dài lên đến 6 và bạn sẽ nhận lại 308.915.776 chuỗi. Những con số này nhận được rất lớn, rất nhanh chóng.

Đây là một giải pháp tôi đưa vào Java. Bạn sẽ cần cung cấp hai đối số thời gian chạy (tương ứng với x và y). Chúc vui vẻ.

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

Thời gian dài nhưng bạn không tạo ra chúng với sự lặp lại?
Kakira

5

Đây là phiên bản không đệ quy mà tôi đã nghĩ ra, trong javascript. Nó không dựa trên cơ sở không đệ quy của Knuth ở trên, mặc dù nó có một số điểm tương đồng trong việc hoán đổi thành phần. Tôi đã xác minh tính chính xác của nó cho các mảng đầu vào lên tới 8 phần tử.

Một tối ưu hóa nhanh chóng sẽ được bay trước outmảng và tránh push().

Ý tưởng cơ bản là:

  1. Đưa ra một mảng nguồn duy nhất, tạo ra một mảng các mảng mới đầu tiên lần lượt hoán đổi phần tử đầu tiên với từng phần tử tiếp theo, mỗi lần để các phần tử khác không bị xáo trộn. ví dụ: đã cho 1234, tạo 1234, 2134, 3214, 4231.

  2. Sử dụng từng mảng từ đường chuyền trước làm hạt giống cho đường chuyền mới, nhưng thay vì hoán đổi phần tử đầu tiên, hãy hoán đổi phần tử thứ hai với mỗi phần tử tiếp theo. Ngoài ra, lần này, không bao gồm mảng ban đầu trong đầu ra.

  3. Lặp lại bước 2 cho đến khi hoàn thành.

Đây là mẫu mã:

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

Trong hồng ngọc:

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

Nó khá nhanh, nhưng sẽ mất một chút thời gian =). Tất nhiên, bạn có thể bắt đầu tại "aaaaaaaa" nếu các chuỗi ngắn không thú vị với bạn.

Tôi có thể đã giải thích sai câu hỏi thực tế - trong một trong những bài đăng có vẻ như bạn chỉ cần một thư viện chuỗi bruteforce, nhưng trong câu hỏi chính có vẻ như bạn cần phải hoán vị một chuỗi cụ thể.

Vấn đề của bạn có phần giống với vấn đề này: http://beust.com/weblog/archives/000491.html (liệt kê tất cả các số nguyên trong đó không có chữ số nào lặp lại, dẫn đến rất nhiều ngôn ngữ giải quyết nó, với anh chàng ocaml sử dụng hoán vị và một số anh chàng java sử dụng một giải pháp khác).


Một vấn đề với đề xuất của bạn là str.next! sẽ không lặp đi lặp lại trên tất cả các ký tự có thể in. Ví dụ của bạn sẽ chỉ tạo các chữ cái viết thường - không có dấu chấm câu hoặc chữ in hoa.
Jarsen

3

Tôi cần điều này ngày hôm nay, và mặc dù các câu trả lời đã đưa tôi đi đúng hướng, nhưng chúng không hoàn toàn như những gì tôi muốn.

Đây là một triển khai bằng phương pháp của Heap. Độ dài của mảng phải ít nhất là 3 và để xem xét thực tế không lớn hơn 10 hoặc hơn, tùy thuộc vào những gì bạn muốn làm, sự kiên nhẫn và tốc độ đồng hồ.

Trước khi bạn vào vòng lặp của mình, hãy khởi tạo Perm(1 To N)với hoán vị đầu tiên, Stack(3 To N)với số 0 * và Levelvới 2**. Khi kết thúc cuộc gọi vòng lặp NextPerm, sẽ trả về false khi chúng ta hoàn thành.

* VB sẽ làm điều đó cho bạn.

** Bạn có thể thay đổi NextPerm một chút để làm cho điều này không cần thiết, nhưng nó rõ ràng hơn như thế này.

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

Các phương pháp khác được mô tả bởi các tác giả khác nhau. Knuth mô tả hai, một cho thứ tự từ vựng, nhưng phức tạp và chậm, cái còn lại được gọi là phương pháp thay đổi đơn giản. Jie Gao và Dianjun Wang cũng đã viết một bài báo thú vị.


2

Mã này trong python, khi được gọi với allowed_charactersset [0,1]và max 4 ký tự, sẽ tạo ra 2 ^ 4 kết quả:

['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()

Hy vọng điều này là sử dụng cho bạn. Hoạt động với bất kỳ ký tự nào, không chỉ số


Đây không phải là hoán vị mà là lựa chọn tập hợp con, tức là ABC & 001 = C trong khi hoán vị hợp lệ phải có cả ba ký tự.
Schultz9999

ừ xin lỗi tôi không hiểu bạn nói gì Nếu bạn sửa nó để lại một phiên bản cố định, tôi sẽ cộng đồng wiki điều đó
droope


0

Mặc dù điều này không trả lời chính xác câu hỏi của bạn, đây là một cách để tạo ra mọi hoán vị của các chữ cái từ một số chuỗi có cùng độ dài: ví dụ: nếu các từ của bạn là "coffee", "j Joomla" và "moodle", bạn có thể mong đợi đầu ra như "coodle", "joodee", "joffle", v.v.

Về cơ bản, số lượng kết hợp là (số lượng từ) cho sức mạnh của (số lượng chữ cái trên mỗi từ). Vì vậy, chọn một số ngẫu nhiên trong khoảng từ 0 đến số kết hợp - 1, chuyển đổi số đó thành cơ sở (số từ), sau đó sử dụng mỗi chữ số của số đó làm chỉ báo cho từ nào sẽ lấy chữ cái tiếp theo.

ví dụ: trong ví dụ trên. 3 từ, 6 chữ cái = 729 kết hợp. Chọn một số ngẫu nhiên: 465. Chuyển đổi sang cơ sở 3: 122020. Lấy chữ cái đầu tiên từ từ 1, 2 từ từ 2, 3 từ từ 2, 4 từ từ 0 ... và bạn nhận được ... "joofle".

Nếu bạn muốn tất cả các hoán vị, chỉ cần lặp từ 0 đến 728. Tất nhiên, nếu bạn chỉ chọn một giá trị ngẫu nhiên, một cách đơn giản hơn ít gây nhầm lẫn sẽ là lặp qua các chữ cái. Phương pháp này cho phép bạn tránh đệ quy, nếu bạn muốn tất cả các hoán vị, cộng với nó làm cho bạn trông giống như bạn biết Toán học (tm) !

Nếu số lượng kết hợp quá nhiều, bạn có thể chia nó thành một chuỗi các từ nhỏ hơn và ghép chúng ở cuối.


0

c # lặp đi lặp lại:

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

Đây là nhận của tôi về một phiên bản không đệ quy


0

Các giải pháp pythonic:

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

0

Vâng đây là một giải pháp O (n!) Thanh lịch, không đệ quy:

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;
    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.