Tạo tất cả các hoán vị của một chuỗi nhất định


418

Một cách thanh lịch để tìm tất cả các hoán vị của một chuỗi. Ví dụ hoán vị cho ba, sẽ là baab, nhưng những gì về chuỗi dài như abcdefgh? Có ví dụ triển khai Java nào không?


3
Có rất nhiều câu trả lời ở đây: stackoverflow.com/questions/361/
Marek Sapota

đây là một câu hỏi rất phổ biến bạn có thể xem tại đây: careercup.com/question?id=3861299
JJunior

9
Có một giả định cần được đề cập. Các nhân vật là duy nhất. Ví dụ: đối với Chuỗi "aaaa" chỉ có một câu trả lời. Để có câu trả lời tổng quát hơn, bạn có thể lưu các chuỗi trong một bộ để tránh trùng lặp
Afshin Moazami

1
Là sự lặp lại của các ký tự được cho phép, hoặc là sự lặp lại của các nhân vật không được phép? Một chuỗi có thể có nhiều lần xuất hiện của cùng một ký tự không?
Anderson Green

2
Đọc lý thuyết (hoặc nếu như tôi, bạn lười biếng, hãy truy cập en.wikipedia.org/wiki/Permuting ) và thực hiện một thuật toán thực sự. Về cơ bản, bạn có thể tạo ra một chuỗi các thứ tự của các phần tử (thực tế rằng đó là một chuỗi không liên quan) và đi qua các thứ tự cho đến khi bạn quay lại từ đầu. Tránh xa bất cứ điều gì liên quan đến đệ quy hoặc thao tác chuỗi.
RèmDog

Câu trả lời:


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

(thông qua Giới thiệu về lập trình trong Java )


67
Giải pháp dường như được phát ra từ đây introcs.cs.princeton.edu/java/23recursion/...
cyber-sư

48
Đó không phải là khoa học tên lửa, tôi đã đưa ra khá nhiều câu trả lời tương tự. Tinh chỉnh nhỏ: thay vì đệ quy cho đến khi n==0, bạn có thể dừng một mức trước đó tại n==1và in ra prefix + str.
lambshaanxy

7
"thời gian và không gian phức tạp của cái này là gì?" không có một số loại bộ nhớ đệm trả lời một phần bất kỳ thuật toán nào tạo ra hoán vị là o (n!) vì kết quả được đặt cho câu hỏi hoán vị là yếu tố đầu vào.
jeremyjjbrown

9
Thanh lịch, đúng vậy. Nhưng một giải pháp chuyển đổi thành một mảng char và hoán đổi để tạo ra các hoán vị sẽ yêu cầu sao chép ít hơn nhiều và tạo ra ít rác hơn nhiều. Ngoài ra thuật toán này không đưa các ký tự lặp lại vào tài khoản.
Gene

20
@AfshinMoazami Tôi nghĩ str.sub chuỗi (i + 1, n) có thể được thay thế bằng str.sub chuỗi (i + 1). Sử dụng str.sub chuỗi (i) sẽ gây ra java.lang.StackOverflowError.
Ayusman

196

Sử dụng đệ quy.

  • Hãy thử lần lượt từng chữ cái là chữ cái đầu tiên và sau đó tìm tất cả các hoán vị của các chữ cái còn lại bằng cách sử dụng một cuộc gọi đệ quy.
  • Trường hợp cơ sở là khi đầu vào là một chuỗi rỗng, hoán vị duy nhất là chuỗi trống.

3
Làm thế nào bạn có thể thêm một kiểu trả về cho phương thức hoán vị? trình biên dịch không thể xác định kiểu trả về của phương thức này ở mỗi lần lặp, mặc dù rõ ràng đó là kiểu String.
dùng1712095

Làm thế nào để bạn đảm bảo hoán vị khác biệt trong phương pháp này?
kapad

70

Đây là giải pháp của tôi dựa trên ý tưởng của cuốn sách "Bẻ khóa phỏng vấn mã hóa" (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;
}

Chạy đầu ra của chuỗi "abcd":

  • Bước 1: Hợp nhất [a] và b: [ba, ab]

  • Bước 2: Hợp nhất [ba, ab] và c: [cba, bca, bac, cab, acb, abc]

  • Bước 3: Hợp nhất [cba, bca, bac, cab, acb, abc] và 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]


Trang (71) trong Bẻ khóa Sách phỏng vấn mã hóa, tái bản lần thứ 6. :)
KarimIhab

5
Đây thực sự là một giải pháp tốt? Nó phụ thuộc vào việc lưu trữ các kết quả trong một danh sách, do đó, đối với một chuỗi đầu vào ngắn, nó phát triển ngoài tầm kiểm soát.
Androrider

hợp nhất làm gì?
Basavaraj Walikar

Nó chèn c vào mọi vị trí có thể có của mỗi chuỗi trong danh sách, vì vậy nếu danh sách chỉ chứa ["b"] và c là "a" thì kết quả hợp nhất là ["ab", "ba"] ở đây cùng một giải pháp với Swift gist.github. com / daniaDlbani / 3bc10e02541f9ba 310d546040c5322fc
Dania Delbani

53

Trong tất cả các giải pháp được đưa ra ở đây và trong các diễn đàn khác, tôi thích Mark Byers nhất. Mô tả đó thực sự khiến tôi suy nghĩ và tự viết mã. Quá tệ, tôi không thể bình chọn giải pháp của anh ấy vì tôi là người mới.
Dù sao ở đây là việc tôi thực hiện mô tả của mình

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

Tôi thích giải pháp này trước giải pháp đầu tiên trong luồng này vì giải pháp này sử dụng StringBuffer. Tôi sẽ không nói rằng giải pháp của tôi không tạo ra bất kỳ chuỗi tạm thời nào (nó thực sự hoạt động ở system.out.printlnnơi toString()StringBuffer được gọi). Nhưng tôi chỉ cảm thấy điều này tốt hơn giải pháp đầu tiên nơi có quá nhiều chuỗi ký tự được tạo ra. Có thể một số anh chàng biểu diễn ngoài kia có thể đánh giá điều này về 'bộ nhớ' (trong 'thời gian', nó đã bị chậm lại do 'trao đổi' thêm đó)


Tại sao không chỉ làm if(index == str.length())doPerm(str, index + 1);? Có currPosvẻ như không cần thiết ở đây.
Robur_131

Xin lỗi, bạn có thể giải thích thêm về câu hỏi không? Có phải bạn đang đề nghị không sử dụng thêm dòng biếnPP (được sử dụng vì nhiều lần xuất hiện và cũng có thể đọc được) nếu không vui lòng dán giải pháp mà bạn đang đề nghị xem xét
srikanth yaradla

Ah tôi hiểu rằng bạn có nghĩa là thay đổi điều kiện cơ bản với lập chỉ mục chuyển tiếp. Hoạt động tốt. Chỉ là giải pháp tôi trình bày hầu hết bị ảnh hưởng bởi các giải pháp khác sau đó thường truyền chuỗi bị cắt hơn là nguyên bản (trường hợp 0 ​​có ý nghĩa). Tuy nhiên cảm ơn đã chỉ. Sẽ xem nếu tôi có thể chỉnh sửa, đã nhiều năm kể từ khi tôi đăng nhập vào trang web này.
srikanth yaradla

22

Một giải pháp rất cơ bản trong Java là sử dụng đệ quy + Set (để tránh lặp lại) nếu bạn muốn lưu trữ và trả về chuỗi giải pháp:

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
Độ phức tạp thời gian của alogrithm này là gì ??
ashisahu

1
@ashisahu O (n!) vì chúng tôi có n! hoán vị trong một chuỗi có độ dài n cho trước.
Zok

17

Tất cả những người đóng góp trước đây đã làm một công việc tuyệt vời để giải thích và cung cấp mã. Tôi nghĩ tôi cũng nên chia sẻ cách tiếp cận này vì nó cũng có thể giúp được ai đó. Giải pháp dựa trên ( thuật toán heaps )

Đôi điều:

  1. Lưu ý mục cuối cùng được mô tả trong excel chỉ là để giúp bạn hình dung rõ hơn logic. Vì vậy, các giá trị thực tế trong cột cuối cùng sẽ là 2,1,0 (nếu chúng ta chạy mã vì chúng ta đang xử lý các mảng và mảng bắt đầu bằng 0).

  2. Thuật toán hoán đổi xảy ra dựa trên các giá trị chẵn hoặc lẻ của vị trí hiện tại. Sẽ rất tự giải thích nếu bạn nhìn vào nơi phương thức hoán đổi được gọi. Bạn có thể thấy những gì đang diễn ra.

Đây là những gì xảy ra: nhập mô tả hình ảnh ở đây

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

Điều này là không có đệ quy

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

Giải pháp này có vẻ sai System.out.println(permute("AABBC").size());hiển thị 45, nhưng thực tế là 5! = 120
Mladen Adamovic

11

Hãy sử dụng đầu vào abclàm ví dụ.

Bắt đầu chỉ với phần tử cuối cùng ( c) trong một tập hợp ( ["c"]), sau đó thêm phần tử cuối cùng thứ hai ( b) vào trước, kết thúc và mọi vị trí có thể ở giữa, làm cho nó ["bc", "cb"]và sau đó theo cách tương tự, nó sẽ thêm phần tử tiếp theo từ back ( a) đến từng chuỗi trong tập hợp tạo nó:

"a" + "bc" = ["abc", "bac", "bca"]  and  "a" + "cb" = ["acb" ,"cab", "cba"] 

Do đó toàn bộ hoán vị:

["abc", "bac", "bca","acb" ,"cab", "cba"]

Mã số:

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
Tôi yêu giải pháp của bạn. Rất trực quan và giải thích tốt. Cảm ơn rât nhiều.
dùng2585781

9

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

Giải pháp này chỉ hoạt động nếu từ có ít hơn 4 chữ cái, nếu không thì chỉ một nửa mảng kết quả chứa các từ duy nhất.
Maksim Maksimov

5

Một trong những giải pháp đơn giản có thể là tiếp tục hoán đổi các ký tự theo cách đệ quy bằng hai con trỏ.

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

Điều này tương tự như giải pháp được đưa ra ở đây: geekforgeek.org/ , liên quan đến việc quay lui và độ phức tạp thời gian O (n * n!).
Nakul Kumar

5

thực hiện trăn

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

điều này làm việc cho tôi ..

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

Sử dụng đệ quy.

khi đầu vào là một chuỗi rỗng, hoán vị duy nhất là một chuỗi rỗng. Hãy thử từng chữ cái trong chuỗi bằng cách đặt nó làm chữ cái đầu tiên và sau đó tìm tất cả các hoán vị của các chữ cái còn lại bằng cách sử dụng lệnh gọi đệ quy.

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

Hãy để tôi thử giải quyết vấn đề này với 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) }
    }
}

Khái niệm cốt lõi: Chia nhỏ danh sách dài thành danh sách nhỏ hơn + đệ quy

Câu trả lời dài với danh sách ví dụ [1, 2, 3, 4]:

Ngay cả đối với một danh sách gồm 4 điều, thật khó hiểu khi cố gắng liệt kê tất cả các hoán vị có thể có trong đầu bạn, và những gì chúng ta cần làm là chính xác để tránh điều đó. Chúng ta dễ dàng hiểu cách tạo ra tất cả các hoán vị của danh sách kích thước 0, 1 và 2, vì vậy tất cả những gì chúng ta cần làm là chia chúng thành bất kỳ kích thước nào và kết hợp chúng lại một cách chính xác. Hãy tưởng tượng một máy jackpot: thuật toán này sẽ bắt đầu quay từ phải sang trái và viết xuống

  1. trả về sản phẩm nào / danh sách 1 khi kích thước danh sách là 0 hoặc 1
  2. xử lý khi kích thước danh sách là 2 (ví dụ [3, 4]) và tạo 2 hoán vị ([3, 4] & [4, 3])
  3. Đối với mỗi mục, đánh dấu là cuối cùng cuối cùng và tìm tất cả các hoán vị cho phần còn lại của mục trong danh sách. (ví dụ: đặt [4] trên bàn và ném [1, 2, 3] vào hoán vị một lần nữa)
  4. Bây giờ với tất cả các hoán vị đó là trẻ em, hãy đặt nó trở lại vào cuối danh sách (ví dụ: [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

Đây là một giải pháp đệ quy tối giản đơn giản trong 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

Chúng ta có thể sử dụng giai thừa để tìm xem có bao nhiêu chuỗi bắt đầu bằng chữ cái cụ thể.

Ví dụ: lấy đầu vào abcd. (3!) == 6chuỗi sẽ bắt đầu với mỗi chữ cái của 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

Đây là những gì tôi đã làm thông qua sự hiểu biết cơ bản về phép gọi và hàm gọi đệ quy. Mất một chút thời gian nhưng nó được thực hiện độc lập.

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

tạo ra đầu ra như [abc, acb, bac, bca, cab, cba].

Logic cơ bản đằng sau nó là

Đối với mỗi nhân vật, hãy coi đó là nhân vật thứ 1 và tìm sự kết hợp của các nhân vật còn lại. ví dụ [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}

Và sau đó gọi đệ quy từng cái [bc], [ac]& [ab]độc lập.


2

Thực hiện Java mà không cần đệ quy

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

// chèn từng ký tự vào một danh sách mảng

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

Tôi không tìm thấy câu trả lời này hữu ích vì nó không chứa lời giải thích và nó sử dụng các thuật toán tương tự như một vài câu trả lời khác mà làm cung cấp một lời giải thích.
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

Một cách đơn giản khác là lặp qua chuỗi, chọn ký tự chưa được sử dụng và đặt nó vào bộ đệm, tiếp tục vòng lặp cho đến khi kích thước bộ đệm bằng với độ dài chuỗi. Tôi thích giải pháp theo dõi trở lại này tốt hơn bởi vì:

  1. Dễ hiểu
  2. Dễ dàng tránh trùng lặp
  3. Đầu ra được sắp xếp

Đây là mã 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;
    }
  }
}

Đầu vào str: 1231

Danh sách đầu ra: {1123, 1132, 1213, 1231, 1312, 1321, 2113, 2131, 2311, 3112, 3121, 3211}

Lưu ý rằng đầu ra được sắp xếp, và không có kết quả trùng lặp.


1

Đệ quy là không cần thiết, thậm chí bạn có thể tính toán bất kỳ hoán vị trực tiếp , giải pháp này sử dụng tổng quát để hoán vị bất kỳ mảng nào.

Đây là một thông tin tốt về thuật toán này.

Đối với các nhà phát triển C # ở đây là triển khai hữu ích hơn.

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

Thuật toán này có độ phức tạp thời giankhông gian O (N) để tính toán từng hoán vị .

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

Hoán vị của chuỗi:

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

Đây là một phương pháp đơn giản hơn để thực hiện Hoán vị của một chuỗi.

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

Việc triển khai java để in tất cả các hoán vị của một chuỗi đã cho xem xét các ký tự trùng lặp và chỉ in các ký tự duy nhất như sau:

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

Điều này có thể được thực hiện lặp đi lặp lại bằng cách chỉ cần lần lượt chèn từng chữ cái của chuỗi trong tất cả các vị trí của kết quả một phần trước đó.

Chúng tôi bắt đầu với [A], mà Btrở thành [BA, AB], và với C, [CBA, BCA, BAC, CAB, etc].

Thời gian chạy sẽ là O(n!), trong trường hợp thử nghiệm ABCD, là1 x 2 x 3 x 4 .

Trong các sản phẩm trên, 1là cho A, 2là cho B, vv

Mẫu phi tiêu:

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

Đây là một triển khai 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

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.