สร้างการเรียงสับเปลี่ยนทั้งหมดของสตริงที่กำหนด


418

เป็นวิธีที่สง่าในการค้นหาพีชคณิตทั้งหมดของสตริงอะไร เช่นการเรียงสับเปลี่ยนสำหรับbaจะเป็นbaและabแต่สิ่งที่เกี่ยวกับสตริงอีกต่อไปเช่นabcdefgh? มีตัวอย่างการติดตั้ง Java หรือไม่?


3
มีคำตอบมากมายที่นี่: stackoverflow.com/questions/361/…
Marek Sapota

นี่เป็นคำถามยอดนิยม คุณสามารถดูได้ที่นี่: careercup.com/question?id=3861299
JJunior

9
จำเป็นต้องมีการกล่าวถึงสมมติฐาน ตัวละครมีความเป็นเอกลักษณ์ ตัวอย่างเช่นสำหรับสตริง "aaaa" มีเพียงคำตอบเดียว เพื่อให้ได้คำตอบที่กว้างขึ้นคุณสามารถบันทึกสตริงในชุดเพื่อหลีกเลี่ยงการซ้ำซ้อน
Afshin 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/ …
ไซเบอร์พระภิกษุสงฆ์

48
นั่นไม่ใช่วิทยาศาสตร์จรวดฉันได้คำตอบที่เหมือนกัน ปรับแต่งเล็ก ๆ น้อย ๆ : แทน recursing จนกว่าn==0คุณสามารถหยุดระดับก่อนหน้านี้ที่และพิมพ์ออกมาn==1 prefix + str
lambshaanxy

7
"ความซับซ้อนของเวลาและพื้นที่ของสิ่งนี้คืออะไร" โดยไม่มีคำตอบบางส่วนแคชอัลกอริทึมใด ๆ ที่ผลการเปลี่ยนแปลงคือ o (n!) เพราะผลลัพธ์ที่ตั้งคำถามการเปลี่ยนแปลงเป็นปัจจัยที่ป้อนเข้า
jeremyjjbrown

9
สง่างามใช่ แต่โซลูชันที่แปลงเป็นอาร์เรย์ char และ swaps เพื่อสร้างการเรียงสับเปลี่ยนจะต้องใช้การคัดลอกและสร้างขยะน้อยลง นอกจากนี้อัลกอริทึมนี้ไม่สามารถพิจารณาตัวละครซ้ำ
ยีน

20
@AfshinMoazami ฉันคิดว่า str.substring (i + 1, n) สามารถถูกแทนที่ด้วย str.substring (i + 1) การใช้ str.substring (i) จะทำให้ java.lang.StackOverflowError
Ayusman

196

ใช้การเรียกซ้ำ

  • ลองใช้ตัวอักษรแต่ละตัวเป็นตัวอักษรตัวแรกจากนั้นค้นหาการเรียงสับเปลี่ยนทั้งหมดของตัวอักษรที่เหลือโดยใช้การโทรซ้ำ
  • กรณีพื้นฐานคือเมื่ออินพุตเป็นสตริงว่างการเรียงสับเปลี่ยนเพียงอย่างเดียวคือสตริงว่าง

3
คุณจะเพิ่มประเภทการคืนลงในวิธีการเปลี่ยนแปลงได้อย่างไร คอมไพเลอร์ไม่สามารถระบุประเภทการส่งคืนของวิธีนี้ได้ในทุกการวนซ้ำแม้ว่าจะเป็นประเภทสตริงก็ตาม
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, acb, abc] และ d: [dcba, cdba, cbda, cbad, dbca, bdca, bcda, bcad, dbac, bdac, badc, dcab, Cadb , cabd, dacb, adcb, acdb, acbd, dabc, adbc, abdc, abcd]


หน้า (71) ในแคร็กสัมภาษณ์หนังสือเข้ารหัสรุ่นที่ 6 :)
KarimIhab

5
นี่เป็นทางออกที่ดีใช่หรือไม่ มันขึ้นอยู่กับการจัดเก็บผลลัพธ์ในรายการดังนั้นสำหรับสตริงอินพุตสั้น ๆ ที่มันไม่สามารถควบคุมได้
Androrider

การผสานทำอะไร
Basavaraj Walikar

มันแทรก c ในทุกตำแหน่งที่เป็นไปได้ของแต่ละสตริงในรายการดังนั้นหากรายการมีเพียง["b"]และ c คือ"a"ผลการรวมคือ["ab", "ba"] ที่นี่มีทางออกเดียวกันกับSwift gist.github com / daniaDlbani / 3bc10e02541f9ba310d546040c5322fc
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 ฉันจะไม่พูดว่าโซลูชันของฉันไม่ได้สร้างสตริงชั่วคราวใด ๆ (จริง ๆ แล้วมันจะทำในsystem.out.printlnที่toString()ของ StringBuffer เรียกว่า) แต่ฉันแค่รู้สึกว่านี่ดีกว่าวิธีแรกที่สร้างสตริงตัวอักษรมากเกินไป อาจเป็นนักแสดงบางคนที่มีประสิทธิภาพสามารถประเมินสิ่งนี้ในแง่ของ 'หน่วยความจำ' (สำหรับ 'เวลา' มันล่าช้าแล้วเนื่องจากการ 'สลับ' พิเศษนั้น)


ทำไมไม่ทำif(index == str.length())และเพียงdoPerm(str, index + 1);? currPosดูเหมือนว่าไม่จำเป็นที่นี่
Robur_131

ขออภัยคุณสามารถอธิบายรายละเอียดเพิ่มเติมเกี่ยวกับคำถามได้หรือไม่ คุณเพิ่งจะแนะนำให้ไม่ใช้ตัวแปรพิเศษ currPos (ใช้เพราะเกิดขึ้นหลายครั้งและอ่านง่าย) ถ้าไม่ได้โปรดวางโซลูชันที่คุณแนะนำให้ดู
srikanth yaradla

อ่าฉันเข้าใจแล้วว่าคุณหมายถึงการเปลี่ยนแปลงเงื่อนไขพื้นฐานด้วยการทำดัชนีไปข้างหน้า ทำงานได้ดี เพียงว่าโซลูชันที่ฉันนำเสนอส่วนใหญ่ได้รับอิทธิพลจากวิธีแก้ปัญหาอื่น ๆ ซึ่งมักจะผ่านสตริงที่ถูกตัดทอนมากกว่าเดิม (ซึ่งกรณีที่ 0 เหมาะสม) อย่างไรก็ตามขอบคุณสำหรับการชี้ จะดูว่าฉันสามารถแก้ไขได้หรือไม่นับเป็นปีที่ฉันเข้าสู่เว็บไซต์นี้มาแล้ว
srikanth yaradla

22

โซลูชันพื้นฐานมากใน Java คือใช้การเรียกซ้ำ + Set (เพื่อหลีกเลี่ยงการทำซ้ำ) หากคุณต้องการจัดเก็บและส่งคืนสตริงโซลูชัน:

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
ความซับซ้อนของเวลาของ alogrithm นี้คืออะไร?
ashisahu

1
@ashisahu O (n!) เนื่องจากเรามี n! การเรียงสับเปลี่ยนในสตริงที่กำหนดของความยาว n
โซ

17

ผู้มีส่วนร่วมก่อนหน้าทั้งหมดได้ทำงานที่ยอดเยี่ยมในการอธิบายและให้รหัส ฉันคิดว่าฉันควรแบ่งปันวิธีการนี้เช่นกันเพราะอาจช่วยคนได้ การแก้ปัญหาขึ้นอยู่กับ ( อัลกอริทึมของฮีป )

สองสิ่ง:

  1. สังเกตุรายการสุดท้ายที่ปรากฎใน excel เป็นเพียงการช่วยให้คุณเห็นภาพตรรกะได้ดีขึ้น ดังนั้นค่าจริงในคอลัมน์สุดท้ายจะเป็น 2,1,0 (ถ้าเราต้องเรียกใช้รหัสเพราะเรากำลังจัดการกับอาร์เรย์และอาร์เรย์เริ่มต้นด้วย 0)

  2. อัลกอริทึมการแลกเปลี่ยนเกิดขึ้นตามค่าคู่หรือคี่ของตำแหน่งปัจจุบัน มันอธิบายตัวเองได้ดีมากหากคุณดูว่าวิธีการแลกเปลี่ยนนั้นถูกเรียกใช้ที่ใดคุณจะเห็นว่าเกิดอะไรขึ้น

นี่คือสิ่งที่เกิดขึ้น: ป้อนคำอธิบายรูปภาพที่นี่

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. ส่งคืนค่าว่าง / รายการ 1 เมื่อขนาดรายการเป็น 0 หรือ 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!) == 6abcd

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]เป็น

ตรรกะพื้นฐานที่อยู่เบื้องหลังมันคือ

สำหรับตัวละครแต่ละตัวให้พิจารณาเป็นตัวอักษรตัวที่ 1 และค้นหาการรวมกันของตัวละครที่เหลือ [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. ผลลัพธ์จะถูกจัดเรียง

นี่คือรหัส java:

List<String> permute(String str) {
  if (str == null) {
    return null;
  }

  char[] chars = str.toCharArray();
  boolean[] used = new boolean[chars.length];

  List<String> res = new ArrayList<String>();
  StringBuilder sb = new StringBuilder();

  Arrays.sort(chars);

  helper(chars, used, sb, res);

  return res;
}

void helper(char[] chars, boolean[] used, StringBuilder sb, List<String> res) {
  if (sb.length() == chars.length) {
    res.add(sb.toString());
    return;
  }

  for (int i = 0; i < chars.length; i++) {
    // avoid duplicates
    if (i > 0 && chars[i] == chars[i - 1] && !used[i - 1]) {
      continue;
    }

    // pick the character that has not used yet
    if (!used[i]) {
      used[i] = true;
      sb.append(chars[i]);

      helper(chars, used, sb, res);

      // back tracking
      sb.deleteCharAt(sb.length() - 1);
      used[i] = false;
    }
  }
}

อินพุต str: 1231

รายการเอาท์พุท: {1123, 1132, 1213, 1231, 1312, 1321, 2113, 2131, 2311, 3112, 3121, 3211}

พบว่ามีการเรียงลำดับผลลัพธ์และไม่มีผลลัพธ์ที่ซ้ำกัน


1

การเรียกซ้ำไม่จำเป็นแม้ว่าคุณจะสามารถคำนวณการเปลี่ยนแปลงใด ๆ โดยตรงโซลูชันนี้ใช้ข้อมูลทั่วไปในการเรียงลำดับอาร์เรย์ใด ๆ

นี่คือข้อมูลที่ดีเกี่ยวกับ algorihtm นี้

สำหรับนักพัฒนาC # นี่คือการใช้งานที่มีประโยชน์มากขึ้น

public static void main(String[] args) {
    String word = "12345";

    Character[] array = ArrayUtils.toObject(word.toCharArray());
    long[] factorials = Permutation.getFactorials(array.length + 1);

    for (long i = 0; i < factorials[array.length]; i++) {
        Character[] permutation = Permutation.<Character>getPermutation(i, array, factorials);
        printPermutation(permutation);
    }
}

private static void printPermutation(Character[] permutation) {
    for (int i = 0; i < permutation.length; i++) {
        System.out.print(permutation[i]);
    }
    System.out.println();
}

ขั้นตอนวิธีการนี้มีO (n) เวลาและพื้นที่ซับซ้อนในการคำนวณแต่ละเปลี่ยนแปลง

public class Permutation {
    public static <T> T[] getPermutation(long permutationNumber, T[] array, long[] factorials) {
        int[] sequence = generateSequence(permutationNumber, array.length - 1, factorials);
        T[] permutation = generatePermutation(array, sequence);

        return permutation;
    }

    public static <T> T[] generatePermutation(T[] array, int[] sequence) {
        T[] clone = array.clone();

        for (int i = 0; i < clone.length - 1; i++) {
            swap(clone, i, i + sequence[i]);
        }

        return clone;
    }

    private static int[] generateSequence(long permutationNumber, int size, long[] factorials) {
        int[] sequence = new int[size];

        for (int j = 0; j < sequence.length; j++) {
            long factorial = factorials[sequence.length - j];
            sequence[j] = (int) (permutationNumber / factorial);
            permutationNumber = (int) (permutationNumber % factorial);
        }

        return sequence;
    }

    private static <T> void swap(T[] array, int i, int j) {
        T t = array[i];
        array[i] = array[j];
        array[j] = t;
    }

    public static long[] getFactorials(int length) {
        long[] factorials = new long[length];
        long factor = 1;

        for (int i = 0; i < length; i++) {
            factor *= i <= 1 ? 1 : i;
            factorials[i] = factor;
        }

        return factorials;
    }
}

1

การเรียงสับเปลี่ยนของสตริง:

public static void main(String args[]) {
    permu(0,"ABCD");
}

static void permu(int fixed,String s) {
    char[] chr=s.toCharArray();
    if(fixed==s.length())
        System.out.println(s);
    for(int i=fixed;i<s.length();i++) {
        char c=chr[i];
        chr[i]=chr[fixed];
        chr[fixed]=c;
        permu(fixed+1,new String(chr));
    }   
}

1

นี่เป็นอีกวิธีที่ง่ายกว่าในการทำการเรียงสับเปลี่ยนของสตริง

public class Solution4 {
public static void main(String[] args) {
    String  a = "Protijayi";
  per(a, 0);

}

static void per(String a  , int start ) {
      //bse case;
    if(a.length() == start) {System.out.println(a);}
    char[] ca = a.toCharArray();
    //swap 
    for (int i = start; i < ca.length; i++) {
        char t = ca[i];
        ca[i] = ca[start];
        ca[start] = t;
        per(new String(ca),start+1);
    }

}//per

}

1

การนำ Java ไปใช้เพื่อพิมพ์พีชคณิตทั้งหมดของสตริงที่กำหนดโดยพิจารณาอักขระที่ซ้ำกันและพิมพ์เฉพาะอักขระที่ไม่ซ้ำกันดังต่อไปนี้:

import java.util.Set;
import java.util.HashSet;

public class PrintAllPermutations2
{
    public static void main(String[] args)
    {
        String str = "AAC";

    PrintAllPermutations2 permutation = new PrintAllPermutations2();

    Set<String> uniqueStrings = new HashSet<>();

    permutation.permute("", str, uniqueStrings);
}

void permute(String prefixString, String s, Set<String> set)
{
    int n = s.length();

    if(n == 0)
    {
        if(!set.contains(prefixString))
        {
            System.out.println(prefixString);
            set.add(prefixString);
        }
    }
    else
    {
        for(int i=0; i<n; i++)
        {
            permute(prefixString + s.charAt(i), s.substring(0,i) + s.substring(i+1,n), set);
        }
    }
}
}

0
/*
     * eg: abc =>{a,bc},{b,ac},{c,ab}
     * =>{ca,b},{cb,a}
     * =>cba,cab
     * =>{ba,c},{bc,a}
     * =>bca,bac
     * =>{ab,c},{ac,b}
     * =>acb,abc
     */
    public void nonRecpermute(String prefix, String word)
    {
        String[] currentstr ={prefix,word};
        Stack<String[]> stack = new Stack<String[]>();
        stack.add(currentstr);
        while(!stack.isEmpty())
        {
            currentstr = stack.pop();
            String currentPrefix = currentstr[0];
            String currentWord = currentstr[1];
            if(currentWord.equals(""))
            {
                System.out.println("Word ="+currentPrefix);
            }
            for(int i=0;i<currentWord.length();i++)
            {
                String[] newstr = new String[2];
                newstr[0]=currentPrefix + String.valueOf(currentWord.charAt(i));
                newstr[1] = currentWord.substring(0, i);
                if(i<currentWord.length()-1)
                {
                    newstr[1] = newstr[1]+currentWord.substring(i+1);
                }
                stack.push(newstr);
            }

        }

    }

0

สิ่งนี้สามารถทำได้ซ้ำ ๆ โดยใส่ตัวอักษรแต่ละตัวของสตริงในสถานที่ทั้งหมดของผลลัพธ์บางส่วนก่อนหน้านี้

เราเริ่มต้นด้วย[A]ซึ่งมีBกลายเป็น[BA, AB]และมีC,[CBA, BCA, BAC, CAB, etc] .

เวลาทำงานจะเป็นO(n!)ที่สำหรับกรณีทดสอบเป็นABCD1 x 2 x 3 x 4

ในผลิตภัณฑ์ด้านบน1มีไว้สำหรับAใช้ทำ2เพื่อ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.