【问题标题】:Generating all permutations of a given string生成给定字符串的所有排列
【发布时间】:2011-05-13 12:13:36
【问题描述】:

找到字符串的所有排列的优雅方法是什么?例如。 ba 的排列将是 baab,但是像 abcdefgh 这样的更长的字符串呢?有Java实现例子吗?

【问题讨论】:

  • 这里有很多答案:stackoverflow.com/questions/361/…
  • 这是一个非常受欢迎的问题。你可以看这里:careercup.com/question?id=3861299
  • 有一个假设需要提及。人物是独一无二的。例如,对于字符串“aaaa”,只有一个答案。要获得更一般的答案,您可以将字符串保存在一个集合中以避免重复
  • 是允许重复字符,还是不允许重复字符?一个字符串可以多次出现同一个字符吗?
  • 阅读理论(或者如果你像我一样懒惰,去en.wikipedia.org/wiki/Permutation)并实现一个真正的算法。基本上你可以生成一系列元素的排序(事实上它是一个字符串是无关紧要的)并遍历这些排序直到你回到开始。避开任何涉及递归或字符串操作的事情。

标签: java algorithm


【解决方案1】:
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));
    }
}

(通过Introduction to Programming in Java

【讨论】:

  • 解决方案似乎来自这里introcs.cs.princeton.edu/java/23recursion/…
  • 这不是火箭科学,我想出了几乎相同的答案。小调整:您可以在n==1 更早停止一个级别并打印出prefix + str,而不是递归到n==0
  • "这个时间和空间复杂度是多少?"没有某种部分答案缓存任何输出排列的算法都是 o(n!) 因为排列问题的结果集是输入的阶乘。
  • 优雅,是的。但是,转换为 char 数组并交换以生成排列的解决方案将需要更少的复制并生成更少的垃圾。该算法也没有考虑到重复的字符。
  • @AfshinMoazami 我认为 str.substring(i+1, n) 可以替换为 str.substring(i+1)。使用 str.substring(i) 会导致 java.lang.StackOverflowError。
【解决方案2】:

使用递归。

  • 依次尝试每个字母作为第一个字母,然后使用递归调用找到其余字母的所有排列。
  • 基本情况是当输入为空字符串时,唯一的排列是空字符串。

【讨论】:

  • 如何为 permute 方法添加返回类型?编译器无法在每次迭代时确定该方法的返回类型,即使它显然是 String 类型。
  • 您如何确保此方法中的不同排列?
【解决方案3】:

这是我基于“Cracking the Coding Interview”(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,bacd,dcab,cdab,cadb,cabd,dacb,adcb,acdb,acbd,dabc,adbc,abdc,abcd]

【讨论】:

  • Cracking the Coding Interview Book,第 6 版中的第 (71) 页。 :)
  • 这真的是一个好的解决方案吗?它依赖于将结果存储在列表中,因此对于较短的输入字符串,它会变得失控。
  • 合并是做什么的?
  • 它将 c 插入列表中每个字符串的每个可能位置,因此如果列表仅包含 ["b"] 并且 c 为 "a"合并结果是 ["ab", "ba"] 这里与 Swift gist.github.com/daniaDlbani/3bc10e02541f9ba310d546040c5322fc 的解决方案相同
【解决方案4】:

在此处和其他论坛中提供的所有解决方案中,我最喜欢 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 中创建的,其中调用了 StringBuffer 的 toString())。但我只是觉得这比创建太多字符串文字的第一个解决方案要好。可能有一些性能专家可以根据“内存”来评估这一点(对于“时间”,由于额外的“交换”,它已经滞后)

【讨论】:

  • 为什么不直接使用if(index == str.length())doPerm(str, index + 1);currPos 在这里似乎没有必要。
  • 对不起,你能详细说明一下这个问题吗?您是否只是建议不要使用额外的变量 currPos(由于多次出现和可读性而使用)如果不是,请粘贴您建议查看的解决方案
  • 啊,我知道您的意思是使用前向索引更改基本条件。工作正常。只是我提出的解决方案主要受当时其他解决方案的影响,这些解决方案通常通过截断的字符串而不是原始的(这种情况 0 有意义)。不过感谢您的指点。看看我能不能编辑,我登录这个网站已经好几年了。
【解决方案5】:

如果您想存储和返回解决方案字符串,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;
}

【讨论】:

  • 这个算法的时间复杂度是多少??
  • @ashisahu O(n!) 因为我们有 n!给定长度为 n 的字符串中的排列。
【解决方案6】:

所有以前的贡献者都在解释和提供代码方面做得很好。我想我也应该分享这种方法,因为它也可能对某人有所帮助。解决方案基于(heaps' algorithm

几件事:

  1. 请注意,excel 中描述的最后一项只是为了帮助您更好地可视化逻辑。因此,最后一列中的实际值将是 2,1,0(如果我们要运行代码,因为我们正在处理数组并且数组以 0 开头)。

  2. 交换算法基于当前位置的偶数或奇数值发生。如果您查看调用 swap 方法的位置,这非常不言自明。您可以看到发生了什么。

会发生以下情况:

public static void main(String[] args) {

        String ourword = "abc";
        String[] ourArray = ourword.split("");
        permute(ourArray, ourArray.length);

    }

    private static void swap(String[] ourarray, int right, int left) {
        String temp = ourarray[right];
        ourarray[right] = ourarray[left];
        ourarray[left] = temp;
    }

    public static void permute(String[] ourArray, int currentPosition) {
        if (currentPosition == 1) {
            System.out.println(Arrays.toString(ourArray));
        } else {
            for (int i = 0; i < currentPosition; i++) {
                // subtract one from the last position (here is where you are
                // selecting the the next last item 
                permute(ourArray, currentPosition - 1);

                // if it's odd position
                if (currentPosition % 2 == 1) {
                    swap(ourArray, 0, currentPosition - 1);
                } else {
                    swap(ourArray, i, currentPosition - 1);
                }
            }
        }
    }

【讨论】:

    【解决方案7】:

    我们以输入 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());
            }
        }
    }
    

    【讨论】:

    • 我喜欢你的解决方案。非常直观且解释清楚。非常感谢。
    【解决方案8】:

    这个没有递归

    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
    【解决方案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 个字母的情况,否则只有一半的结果数组包含唯一单词。
    【解决方案10】:

    一个简单的解决方案可能是使用两个指针递归地交换字符。

    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!)。
    【解决方案11】:

    python 实现

    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','')
    

    【讨论】:

      【解决方案12】:

      这是我通过对排列和递归函数调用的基本了解所做的。需要一点时间,但它是独立完成的。

      public class LexicographicPermutations {
      
      public static void main(String[] args) {
          // TODO Auto-generated method stub
          String s="abc";
          List<String>combinations=new ArrayList<String>();
          combinations=permutations(s);
          Collections.sort(combinations);
          System.out.println(combinations);
      }
      
      private static List<String> permutations(String s) {
          // TODO Auto-generated method stub
          List<String>combinations=new ArrayList<String>();
          if(s.length()==1){
              combinations.add(s);
          }
          else{
              for(int i=0;i<s.length();i++){
                  List<String>temp=permutations(s.substring(0, i)+s.substring(i+1));
                  for (String string : temp) {
                      combinations.add(s.charAt(i)+string);
                  }
              }
          }
          return combinations;
      }}
      

      生成输出[abc, acb, bac, bca, cab, cba]

      其背后的基本逻辑是

      对于每个字符,将其视为第一个字符并找出其余字符的组合。例如[abc](Combination of abc)-&gt;.

      1. a-&gt;[bc](a x Combination of (bc))-&gt;{abc,acb}
      2. b-&gt;[ac](b x Combination of (ac))-&gt;{bac,bca}
      3. c-&gt;[ab](c x Combination of (ab))-&gt;{cab,cba}

      然后独立地递归调用每个[bc],[ac] & [ab]

      【讨论】:

        【解决方案13】:

        使用递归。

        当输入是一个空字符串时,唯一的排列是一个空字符串。尝试将字符串中的每个字母作为第一个字母,然后使用递归调用找到剩余字母的所有排列。

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

        【讨论】:

          【解决方案14】:

          这对我有用..

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

          【讨论】:

            【解决方案15】:

            让我尝试用 Kotlin 解决这个问题:

            fun <T> List<T>.permutations(): List<List<T>> {
                //escape case
                if (this.isEmpty()) return emptyList()
            
                if (this.size == 1) return listOf(this)
            
                if (this.size == 2) return listOf(listOf(this.first(), this.last()), listOf(this.last(), this.first()))
            
                //recursive case
                return this.flatMap { lastItem ->
                    this.minus(lastItem).permutations().map { it.plus(lastItem) }
                }
            }
            

            核心理念:将长列表分解成更小的列表+递归

            带有示例列表的长答案 [1, 2, 3, 4]:

            即使是 4 个列表,尝试列出您脑海中所有可能的排列也已经有点令人困惑,而我们需要做的就是避免这种情况。我们很容易理解如何对大小为 0、1 和 2 的列表进行所有排列,因此我们需要做的就是将它们分解为这些大小中的任何一个并将它们正确组合起来。想象一个中奖机:这个算法会开始从右向左旋转,并写下

            1. 当列表大小为 0 或 1 时返回空列表/列表 1
            2. 当列表大小为 2 时处理(例如 [3, 4]),并生成 2 个排列([3, 4] & [4, 3])
            3. 对于每个项目,将其标记为最后一个,并在列表中找到其余项目的所有排列。 (例如将 [4] 放在桌子上,然后将 [1, 2, 3] 再次放入排列中)
            4. 现在所有排列都是孩子,将自己放回列表的末尾(例如:[1, 2, 3][,4], [1, 3, 2][,4], [2, 3 , 1][, 4], ...)

            【讨论】:

              【解决方案16】:
              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++;
                  }
              
              }
              

              【讨论】:

                【解决方案17】:
                /** 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;
                }
                

                【讨论】:

                  【解决方案18】:

                  这是一个简单的 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;
                  }
                  

                  【讨论】:

                    【解决方案19】:

                    我们可以使用阶乘来找出有多少个以特定字母开头的字符串。

                    示例:输入abcd(3!) == 6 字符串将以abcd 的每个字母开头。

                    static public int facts(int x){
                        int sum = 1;
                        for (int i = 1; i < x; i++) {
                            sum *= (i+1);
                        }
                        return sum;
                    }
                    
                    public static void permutation(String str) {
                        char[] str2 = str.toCharArray();
                        int n = str2.length;
                        int permutation = 0;
                        if (n == 1) {
                            System.out.println(str2[0]);
                        } else if (n == 2) {
                            System.out.println(str2[0] + "" + str2[1]);
                            System.out.println(str2[1] + "" + str2[0]);
                        } else {
                            for (int i = 0; i < n; i++) {
                                if (true) {
                                    char[] str3 = str.toCharArray();
                                    char temp = str3[i];
                                    str3[i] = str3[0];
                                    str3[0] = temp;
                                    str2 = str3;
                                }
                    
                                for (int j = 1, count = 0; count < facts(n-1); j++, count++) {
                                    if (j != n-1) {
                                        char temp1 = str2[j+1];
                                        str2[j+1] = str2[j];
                                        str2[j] = temp1;
                                    } else {
                                        char temp1 = str2[n-1];
                                        str2[n-1] = str2[1];
                                        str2[1] = temp1;
                                        j = 1;
                                    } // end of else block
                                    permutation++;
                                    System.out.print("permutation " + permutation + " is   -> ");
                                    for (int k = 0; k < n; k++) {
                                        System.out.print(str2[k]);
                                    } // end of loop k
                                    System.out.println();
                                } // end of loop j
                            } // end of loop i
                        }
                    }
                    

                    【讨论】:

                      【解决方案20】:

                      没有递归的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;
                      }
                      

                      【讨论】:

                        【解决方案21】:

                        //将每个字符插入到数组列表中

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

                        【讨论】:

                        • 我觉得这个答案没有用,因为它不包含任何解释,并且它使用与 确实 提供解释的其他一些答案相同的算法。
                        【解决方案22】:
                        //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--]);
                                }
                            }
                        }
                        

                        【讨论】:

                          【解决方案23】:

                          另一种简单的方法是遍历字符串,选择尚未使用的字符并将其放入缓冲区,继续循环直到缓冲区大小等于字符串长度。我更喜欢这种回溯解决方案,因为:

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

                          输入字符串:1231

                          输出列表:{1123, 1132, 1213, 1231, 1312, 1321, 2113, 2131, 2311, 3112, 3121, 3211}

                          注意到输出已经排序,没有重复的结果。

                          【讨论】:

                            【解决方案24】:

                            递归不是必须的,即使你可以直接计算任何排列,这个解决方案使用泛型来排列任何数组。

                            Here 是关于这个算法的一个很好的信息。

                            对于 C# 开发人员,here 是更有用的实现。

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

                            【讨论】:

                              【解决方案25】:

                              我的实现基于上面 Mark Byers 的描述:

                                  static Set<String> permutations(String str){
                                      if (str.isEmpty()){
                                          return Collections.singleton(str);
                                      }else{
                                          Set <String> set = new HashSet<>();
                                          for (int i=0; i<str.length(); i++)
                                              for (String s : permutations(str.substring(0, i) + str.substring(i+1)))
                                                  set.add(str.charAt(i) + s);
                                          return set;
                                      }
                                  }
                              

                              【讨论】:

                                【解决方案26】:

                                字符串的排列:

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

                                【讨论】:

                                  【解决方案27】:

                                  这是对字符串进行排列的另一种更简单的方法。

                                  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
                                  
                                  }
                                  

                                  【讨论】:

                                    【解决方案28】:

                                    考虑重复字符并仅打印唯一字符的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);
                                            }
                                        }
                                    }
                                    }
                                    

                                    【讨论】:

                                      【解决方案29】:

                                      使用 Es6 的字符串排列

                                      使用 reduce() 方法

                                      const permutations = str => {
                                        if (str.length <= 2) 
                                        return str.length === 2 ? [str, str[1] + str[0]] : [str];
                                        
                                        return str
                                          .split('')
                                          .reduce(
                                            (acc, letter, index) =>
                                              acc.concat(permutations(str.slice(0, index) + str.slice(index + 1)).map(val => letter + val)),
                                            [] 
                                          );
                                      };
                                      
                                      console.log(permutations('STR'));

                                      【讨论】:

                                        【解决方案30】:

                                        如果有人想要生成排列来对它们做某事,而不是仅仅通过 void 方法打印它们:

                                        static List<int[]> permutations(int n) {
                                        
                                            class Perm {
                                                private final List<int[]> permutations = new ArrayList<>();
                                        
                                                private void perm(int[] array, int step) {
                                                    if (step == 1) permutations.add(array.clone());
                                                    else for (int i = 0; i < step; i++) {
                                                        perm(array, step - 1);
                                                        int j = (step % 2 == 0) ? i : 0;
                                                        swap(array, step - 1, j);
                                                    }
                                                }
                                        
                                                private void swap(int[] array, int i, int j) {
                                                    int buffer = array[i];
                                                    array[i] = array[j];
                                                    array[j] = buffer;
                                                }
                                        
                                            }
                                        
                                            int[] nVector  = new int[n];
                                            for (int i = 0; i < n; i++) nVector [i] = i;
                                        
                                            Perm perm = new Perm();
                                            perm.perm(nVector, n);
                                            return perm.permutations;
                                        
                                        }
                                        

                                        【讨论】:

                                          猜你喜欢
                                          • 2013-12-23
                                          • 2021-02-02
                                          • 1970-01-01
                                          • 2019-12-09
                                          • 1970-01-01
                                          • 1970-01-01
                                          • 2023-03-04
                                          • 2017-05-26
                                          相关资源
                                          最近更新 更多