代码之家  ›  专栏  ›  技术社区  ›  GurdeepS

列出字符串/整数的所有排列

  •  142
  • GurdeepS  · 技术社区  · 15 年前

    在编程面谈中(不是根据我的面谈经验)的一个常见任务是取一个字符串或一个整数并列出所有可能的排列。

    有没有一个例子说明如何做到这一点以及解决这一问题背后的逻辑?

    我见过一些代码片段,但它们没有很好的注释/解释,因此很难理解。

    27 回复  |  直到 6 年前
        1
  •  141
  •   Beska    9 年前

    首先:闻起来像 递归 当然!

    既然你还想知道这个原理,我就尽力解释了。我认为递归在大多数情况下都很容易。你只需要掌握两个步骤:

    1. 第一步
    2. 所有其他步骤(所有步骤都具有相同的逻辑)

    人类语言 :

    简而言之:
    1。一个元素的排列是一个元素。
    2.第2条。一组元素的排列是每个元素的列表,与其他元素的每个排列连接在一起。

    例子:

    如果集合只有一个元素-->
    把它还给我。
    烫发(A)-A

    如果集合有两个字符:用于 其中的每个元素:返回 元素的排列 添加的其他元素,如:

    排列(AB)->

    A+烫发(B)-> 抗体

    B+烫发(A)-> 文学士

    进一步:对于集合中的每个字符:返回一个字符,并与对集合其余部分的详细阅读连接起来

    烫发(ABC)-GT;

    A+烫发(BC)--> abc , ACB

    B+烫发(AC)--> 生物活性炭 , BCA

    C+烫发(AB)--> 驾驶室 , 中国篮球协会

    排列(abc…z)--gt;

    A+烫发(…),B+烫发(…)

    我找到了 伪码 http://www.programmersheaven.com/mb/Algorithms/369713/369713/permutation-algorithm-help/ :

    makePermutations(permutation) {
      if (length permutation < required length) {
        for (i = min digit to max digit) {
          if (i not in permutation) {
            makePermutations(permutation+i)
          }
        }
      }
      else {
        add permutation to list
      }
    }
    

    C.*

    好的,还有更详细的内容(因为它被标记为C),来自 http://radio.weblogs.com/0111551/stories/2002/10/14/permutations.html : 相当冗长,但我还是决定复制它,所以这篇文章不依赖于原文。

    函数获取一个字符串,并写下该字符串的所有可能排列,例如,如果提供了“abc”,则应溢出:

    ABC、ACB、BAC、BCA、驾驶室、CBA。

    代码:

    class Program
    {
        private static void Swap(ref char a, ref char b)
        {
            if (a == b) return;
    
            a ^= b;
            b ^= a;
            a ^= b;
        }
    
        public static void GetPer(char[] list)
        {
            int x = list.Length - 1;
            GetPer(list, 0, x);
        }
    
        private static void GetPer(char[] list, int k, int m)
        {
            if (k == m)
            {
                Console.Write(list);
            }
            else
                for (int i = k; i <= m; i++)
                {
                       Swap(ref list[k], ref list[i]);
                       GetPer(list, k + 1, m);
                       Swap(ref list[k], ref list[i]);
                }
        }
    
        static void Main()
        {
            string str = "sagiv";
            char[] arr = str.ToCharArray();
            GetPer(arr);
        }
    }
    
        2
  •  70
  •   Community chadoh    7 年前

    如果允许使用LINQ,那么这只是两行代码。请看我的答案 here .

    编辑

    下面是我的通用函数,它可以从t的列表中返回所有排列(不是组合):

    static IEnumerable<IEnumerable<T>>
        GetPermutations<T>(IEnumerable<T> list, int length)
    {
        if (length == 1) return list.Select(t => new T[] { t });
    
        return GetPermutations(list, length - 1)
            .SelectMany(t => list.Where(e => !t.Contains(e)),
                (t1, t2) => t1.Concat(new T[] { t2 }));
    }
    

    例子:

    IEnumerable<IEnumerable<int>> result =
        GetPermutations(Enumerable.Range(1, 3), 3);
    

    输出-整数列表:

    {1,2,3} {1,3,2} {2,1,3} {2,3,1} {3,1,2} {3,2,1}
    

    由于此函数使用Linq,因此它需要.NET 3.5或更高版本。

        3
  •  32
  •   Peter Mortensen Aslan Kaya    10 年前

    我在这里找到了解决办法。它是用Java编写的,但是我已经把它转换成C语言了。我希望它能帮助你。

    Enter image description here

    这是C中的代码:

    static void Main(string[] args)
    {
        string str = "ABC";
        char[] charArry = str.ToCharArray();
        permute(charArry, 0, 2);
        Console.ReadKey();
    }
    
    static void permute(char[] arry, int i, int n)
    {
        int j;
        if (i==n)
            Console.WriteLine(arry);
        else
        {
            for(j = i; j <=n; j++)
            {
                swap(ref arry[i],ref arry[j]);
                permute(arry,i+1,n);
                swap(ref arry[i], ref arry[j]); //backtrack
            }
        }
    }
    
    static void swap(ref char a, ref char b)
    {
        char tmp;
        tmp = a;
        a=b;
        b = tmp;
    }
    
        4
  •  19
  •   Community chadoh    7 年前

    递归 不需要, here 是关于此解决方案的良好信息。

    var values1 = new[] { 1, 2, 3, 4, 5 };
    
    foreach (var permutation in values1.GetPermutations())
    {
        Console.WriteLine(string.Join(", ", permutation));
    }
    
    var values2 = new[] { 'a', 'b', 'c', 'd', 'e' };
    
    foreach (var permutation in values2.GetPermutations())
    {
        Console.WriteLine(string.Join(", ", permutation));
    }
    
    Console.ReadLine();
    

    我已经用这个算法很多年了,它 o(n) 时间 空间 每种计算的复杂性 置换 .

    public static class SomeExtensions
    {
        public static IEnumerable<IEnumerable<T>> GetPermutations<T>(this IEnumerable<T> enumerable)
        {
            var array = enumerable as T[] ?? enumerable.ToArray();
    
            var factorials = Enumerable.Range(0, array.Length + 1)
                .Select(Factorial)
                .ToArray();
    
            for (var i = 0L; i < factorials[array.Length]; i++)
            {
                var sequence = GenerateSequence(i, array.Length - 1, factorials);
    
                yield return GeneratePermutation(array, sequence);
            }
        }
    
        private static IEnumerable<T> GeneratePermutation<T>(T[] array, IReadOnlyList<int> sequence)
        {
            var clone = (T[]) array.Clone();
    
            for (int i = 0; i < clone.Length - 1; i++)
            {
                Swap(ref clone[i], ref clone[i + sequence[i]]);
            }
    
            return clone;
        }
    
        private static int[] GenerateSequence(long number, int size, IReadOnlyList<long> factorials)
        {
            var sequence = new int[size];
    
            for (var j = 0; j < sequence.Length; j++)
            {
                var facto = factorials[sequence.Length - j];
    
                sequence[j] = (int)(number / facto);
                number = (int)(number % facto);
            }
    
            return sequence;
        }
    
        static void Swap<T>(ref T a, ref T b)
        {
            T temp = a;
            a = b;
            b = temp;
        }
    
        private static long Factorial(int n)
        {
            long result = n;
    
            for (int i = 1; i < n; i++)
            {
                result = result * i;
            }
    
            return result;
        }
    }
    
        5
  •  11
  •       15 年前
    void permute (char *str, int ptr) {
      int i, len;
      len = strlen(str);
      if (ptr == len) {
        printf ("%s\n", str);
        return;
      }
    
      for (i = ptr ; i < len ; i++) {
        swap (&str[ptr], &str[i]);
        permute (str, ptr + 1);
        swap (&str[ptr], &str[i]);
      }
    }
    

    您可以编写交换函数来交换字符。
    这被称为permute(字符串,0);

        6
  •  9
  •   Can Berk Güder Pugalmuni    15 年前

    首先,集合有排列,不是字符串或整数,所以我假设您的意思是“字符串中的字符集”。

    请注意,一组大小为n的元素有n个!n置换。

    以下伪代码(来自维基百科),用k=1…n调用!将给出所有排列:

    function permutation(k, s) {
        for j = 2 to length(s) {
            swap s[(k mod j) + 1] with s[j]; // note that our array is indexed starting at 1
            k := k / j; // integer division cuts off the remainder
        }
        return s;
    }
    

    下面是等效的python代码(用于基于0的数组索引):

    def permutation(k, s):
        r = s[:]
        for j in range(2, len(s)+1):
            r[j-1], r[k%j] = r[k%j], r[j-1]
            k = k/j+1
        return r
    
        7
  •  6
  •   Yuri Astrakhan    12 年前

    稍微修改过的C语言版本,在任何类型的数组中产生所需的排列。

        // USAGE: create an array of any type, and call Permutations()
        var vals = new[] {"a", "bb", "ccc"};
        foreach (var v in Permutations(vals))
            Console.WriteLine(string.Join(",", v)); // Print values separated by comma
    
    
    public static IEnumerable<T[]> Permutations<T>(T[] values, int fromInd = 0)
    {
        if (fromInd + 1 == values.Length)
            yield return values;
        else
        {
            foreach (var v in Permutations(values, fromInd + 1))
                yield return v;
    
            for (var i = fromInd + 1; i < values.Length; i++)
            {
                SwapValues(values, fromInd, i);
                foreach (var v in Permutations(values, fromInd + 1))
                    yield return v;
                SwapValues(values, fromInd, i);
            }
        }
    }
    
    private static void SwapValues<T>(T[] values, int pos1, int pos2)
    {
        if (pos1 != pos2)
        {
            T tmp = values[pos1];
            values[pos1] = values[pos2];
            values[pos2] = tmp;
        }
    }
    
        8
  •  6
  •   hug    9 年前

    我喜欢 FBRYANT97 因为它很简单。不幸的是,它和许多其他“解决方案”一样,不提供所有排列,或者如果一个整数包含同一个数字多次,则不提供整数。以656123为例。线:

    var tail = chars.Except(new List<char>(){c});
    

    使用except将删除所有事件,即当c=6时,删除两位数字,并保留例如5123。因为我尝试过的所有解决方案都没有解决这个问题,所以我决定自己尝试解决它。 FBRYANT97 的代码作为基。这就是我想到的:

    private static List<string> FindPermutations(string set)
        {
            var output = new List<string>();
            if (set.Length == 1)
            {
                output.Add(set);
            }
            else
            {
                foreach (var c in set)
                {
                    // Remove one occurrence of the char (not all)
                    var tail = set.Remove(set.IndexOf(c), 1);
                    foreach (var tailPerms in FindPermutations(tail))
                    {
                        output.Add(c + tailPerms);
                    }
                }
            }
            return output;
        }
    

    我只是使用.remove和.indexof删除第一个发现的事件。至少对我的使用来说是这样的。我相信它会变得更聪明。

    但是有一点需要注意:结果列表可能包含重复项,因此请确保方法返回(例如哈希集),或者在返回后使用您喜欢的任何方法删除重复项。

        9
  •  5
  •   moinudin    15 年前

    这是一篇很好的文章,介绍了三种查找所有置换的算法,包括一种查找下一个置换的算法。

    http://www.cut-the-knot.org/do_you_know/AllPerm.shtml

    C++和Python有内置的 next_permutation itertools.permutations 各功能。

        10
  •  5
  •   em70    15 年前

    下面是一个纯粹的功能性F实现:

    
    let factorial i =
        let rec fact n x =
            match n with
            | 0 -> 1
            | 1 -> x
            | _ -> fact (n-1) (x*n)
        fact i 1
    
    let swap (arr:'a array) i j = [| for k in 0..(arr.Length-1) -> if k = i then arr.[j] elif k = j then arr.[i] else arr.[k] |]
    
    let rec permutation (k:int,j:int) (r:'a array) =
        if j = (r.Length + 1) then r
        else permutation (k/j+1, j+1) (swap r (j-1) (k%j))
    
    let permutations (source:'a array) = seq { for k = 0 to (source |> Array.length |> factorial) - 1 do yield permutation (k,2) source }
    

    通过更改swap来利用clr数组的可变特性,可以大大提高性能,但是对于源数组,这种实现是线程安全的,在某些情况下可能是可取的。 此外,对于包含16个以上元素的数组,int必须替换为精度更高/任意的类型,因为factorial 17会导致int32溢出。

        11
  •  5
  •   raghavankl    8 年前

    这里有一个使用递归的C中的简单解决方案,

    void Main()
    {
        string word = "abc";
        WordPermuatation("",word);
    }
    
    void WordPermuatation(string prefix, string word)
    {
        int n = word.Length;
        if (n == 0) { Console.WriteLine(prefix); }
        else
        {
            for (int i = 0; i < n; i++)
            {
                WordPermuatation(prefix + word[i],word.Substring(0, i) + word.Substring(i + 1, n - (i+1)));
            }
        }
    }
    
        12
  •  4
  •   Amir Chatrbahr    8 年前

    这里有一个简单易懂的排列函数,用于输入字符串和整数。用这个 甚至可以设置输出长度 (正常情况下等于输入长度)

        static ICollection<string> result;
    
        public static ICollection<string> GetAllPermutations(string str, int outputLength)
        {
            result = new List<string>();
            MakePermutations(str.ToCharArray(), string.Empty, outputLength);
            return result;
        }
    
        private static void MakePermutations(
           char[] possibleArray,//all chars extracted from input
           string permutation,
           int outputLength//the length of output)
        {
             if (permutation.Length < outputLength)
             {
                 for (int i = 0; i < possibleArray.Length; i++)
                 {
                     var tempList = possibleArray.ToList<char>();
                     tempList.RemoveAt(i);
                     MakePermutations(tempList.ToArray(), 
                          string.Concat(permutation, possibleArray[i]), outputLength);
                 }
             }
             else if (!result.Contains(permutation))
                result.Add(permutation);
        }
    

    为了 整数 只需更改调用方方法和 生成排列()。 保持原样:

        public static ICollection<int> GetAllPermutations(int input, int outputLength)
        {
            result = new List<string>();
            MakePermutations(input.ToString().ToCharArray(), string.Empty, outputLength);
            return result.Select(m => int.Parse(m)).ToList<int>();
        }
    

    示例1:GetAllPermutations(“abc”,3); “abc”“acb”“bac”“bca”“cab”“cba”

    示例2:GetAllPermutations(“abcd”,2); “ab”“ac”“ad”“ba”“bc”“bd”“ca”“cb”“cd”“da”“db”“dc”

    示例3:GetAllPermutations(486,2); 48 46 84 86 64 68

        13
  •  2
  •   Amit Patel    13 年前

    这是打印所有排列的函数。 此函数实现由Peter解释的逻辑。

    public class Permutation
    {
        //http://www.java2s.com/Tutorial/Java/0100__Class-Definition/RecursivemethodtofindallpermutationsofaString.htm
    
        public static void permuteString(String beginningString, String endingString)
        {           
    
            if (endingString.Length <= 1)
                Console.WriteLine(beginningString + endingString);
            else
                for (int i = 0; i < endingString.Length; i++)
                {
    
                    String newString = endingString.Substring(0, i) + endingString.Substring(i + 1);
    
                    permuteString(beginningString + endingString.ElementAt(i), newString);
    
                }
        }
    }
    
        static void Main(string[] args)
        {
    
            Permutation.permuteString(String.Empty, "abc");
            Console.ReadLine();
    
        }
    
        14
  •  2
  •   Kevin Gosse    12 年前

    下面是我的排列实现。别介意变量名,因为我是为了好玩才这么做的:)

    class combinations
    {
        static void Main()
        {
    
            string choice = "y";
            do
            {
                try
                {
                    Console.WriteLine("Enter word :");
                    string abc = Console.ReadLine().ToString();
                    Console.WriteLine("Combinatins for word :");
                    List<string> final = comb(abc);
                    int count = 1;
                    foreach (string s in final)
                    {
                        Console.WriteLine("{0} --> {1}", count++, s);
                    }
                    Console.WriteLine("Do you wish to continue(y/n)?");
                    choice = Console.ReadLine().ToString();
                }
                catch (Exception exc)
                {
                    Console.WriteLine(exc);
                }
            } while (choice == "y" || choice == "Y");
        }
    
        static string swap(string test)
        {
            return swap(0, 1, test);
        }
    
        static List<string> comb(string test)
        {
            List<string> sec = new List<string>();
            List<string> first = new List<string>();
            if (test.Length == 1) first.Add(test);
            else if (test.Length == 2) { first.Add(test); first.Add(swap(test)); }
            else if (test.Length > 2)
            {
                sec = generateWords(test);
                foreach (string s in sec)
                {
                    string init = s.Substring(0, 1);
                    string restOfbody = s.Substring(1, s.Length - 1);
    
                    List<string> third = comb(restOfbody);
                    foreach (string s1 in third)
                    {
                        if (!first.Contains(init + s1)) first.Add(init + s1);
                    }
    
    
                }
            }
    
            return first;
        }
    
        static string ShiftBack(string abc)
        {
            char[] arr = abc.ToCharArray();
            char temp = arr[0];
            string wrd = string.Empty;
            for (int i = 1; i < arr.Length; i++)
            {
                wrd += arr[i];
            }
    
            wrd += temp;
            return wrd;
        }
    
        static List<string> generateWords(string test)
        {
            List<string> final = new List<string>();
            if (test.Length == 1)
                final.Add(test);
            else
            {
                final.Add(test);
                string holdString = test;
                while (final.Count < test.Length)
                {
                    holdString = ShiftBack(holdString);
                    final.Add(holdString);
                }
            }
    
            return final;
        }
    
        static string swap(int currentPosition, int targetPosition, string temp)
        {
            char[] arr = temp.ToCharArray();
            char t = arr[currentPosition];
            arr[currentPosition] = arr[targetPosition];
            arr[targetPosition] = t;
            string word = string.Empty;
            for (int i = 0; i < arr.Length; i++)
            {
                word += arr[i];
    
            }
    
            return word;
    
        }
    }
    
        15
  •  2
  •   FBryant87    9 年前

    下面是我写的一个高级示例,它说明了 人类语言 彼得解释说:

        public List<string> FindPermutations(string input)
        {
            if (input.Length == 1)
                return new List<string> { input };
            var perms = new List<string>();
            foreach (var c in input)
            {
                var others = input.Remove(input.IndexOf(c), 1);
                perms.AddRange(FindPermutations(others).Select(perm => c + perm));
            }
            return perms;
        }
    
        16
  •  2
  •   Meng Xue    6 年前
    class Program
    {
        public static void Main(string[] args)
        {
            Permutation("abc");
        }
    
        static void Permutation(string rest, string prefix = "")
        {
            if (string.IsNullOrEmpty(rest)) Console.WriteLine(prefix);
    
            // Each letter has a chance to be permutated
            for (int i = 0; i < rest.Length; i++)
            {                
                Permutation(rest.Remove(i, 1), prefix + rest[i]);
            }
        }
    }
    
        17
  •  1
  •   Eric Ouellet    8 年前

    如果性能和内存是一个问题,我建议这个非常有效的实现。根据 Heap's algorithm in Wikipedia 它应该是最快的。希望它能满足您的需要:—)!

    就像把它与一个10的LINQ实现进行比较一样!(包括代码):

    • 这:235毫秒内36288000件物品
    • LINQ:36288000项,50051毫秒

      using System;
      using System.Collections.Generic;
      using System.Diagnostics;
      using System.Linq;
      using System.Runtime.CompilerServices;
      using System.Text;
      
      namespace WpfPermutations
      {
          /// <summary>
          /// EO: 2016-04-14
          /// Generator of all permutations of an array of anything.
          /// Base on Heap's Algorithm. See: https://en.wikipedia.org/wiki/Heap%27s_algorithm#cite_note-3
          /// </summary>
          public static class Permutations
          {
              /// <summary>
              /// Heap's algorithm to find all pmermutations. Non recursive, more efficient.
              /// </summary>
              /// <param name="items">Items to permute in each possible ways</param>
              /// <param name="funcExecuteAndTellIfShouldStop"></param>
              /// <returns>Return true if cancelled</returns> 
              public static bool ForAllPermutation<T>(T[] items, Func<T[], bool> funcExecuteAndTellIfShouldStop)
              {
                  int countOfItem = items.Length;
      
                  if (countOfItem <= 1)
                  {
                      return funcExecuteAndTellIfShouldStop(items);
                  }
      
                  var indexes = new int[countOfItem];
                  for (int i = 0; i < countOfItem; i++)
                  {
                      indexes[i] = 0;
                  }
      
                  if (funcExecuteAndTellIfShouldStop(items))
                  {
                      return true;
                  }
      
                  for (int i = 1; i < countOfItem;)
                  {
                      if (indexes[i] < i)
                      { // On the web there is an implementation with a multiplication which should be less efficient.
                          if ((i & 1) == 1) // if (i % 2 == 1)  ... more efficient ??? At least the same.
                          {
                              Swap(ref items[i], ref items[indexes[i]]);
                          }
                          else
                          {
                              Swap(ref items[i], ref items[0]);
                          }
      
                          if (funcExecuteAndTellIfShouldStop(items))
                          {
                              return true;
                          }
      
                          indexes[i]++;
                          i = 1;
                      }
                      else
                      {
                          indexes[i++] = 0;
                      }
                  }
      
                  return false;
              }
      
              /// <summary>
              /// This function is to show a linq way but is far less efficient
              /// </summary>
              /// <typeparam name="T"></typeparam>
              /// <param name="list"></param>
              /// <param name="length"></param>
              /// <returns></returns>
              static IEnumerable<IEnumerable<T>> GetPermutations<T>(IEnumerable<T> list, int length)
              {
                  if (length == 1) return list.Select(t => new T[] { t });
      
                  return GetPermutations(list, length - 1)
                      .SelectMany(t => list.Where(e => !t.Contains(e)),
                          (t1, t2) => t1.Concat(new T[] { t2 }));
              }
      
              /// <summary>
              /// Swap 2 elements of same type
              /// </summary>
              /// <typeparam name="T"></typeparam>
              /// <param name="a"></param>
              /// <param name="b"></param>
              [MethodImpl(MethodImplOptions.AggressiveInlining)]
              static void Swap<T>(ref T a, ref T b)
              {
                  T temp = a;
                  a = b;
                  b = temp;
              }
      
              /// <summary>
              /// Func to show how to call. It does a little test for an array of 4 items.
              /// </summary>
              public static void Test()
              {
                  ForAllPermutation("123".ToCharArray(), (vals) =>
                  {
                      Debug.Print(String.Join("", vals));
                      return false;
                  });
      
                  int[] values = new int[] { 0, 1, 2, 4 };
      
                  Debug.Print("Non Linq");
                  ForAllPermutation(values, (vals) =>
                  {
                      Debug.Print(String.Join("", vals));
                      return false;
                  });
      
                  Debug.Print("Linq");
                  foreach(var v in GetPermutations(values, values.Length))
                  {
                      Debug.Print(String.Join("", v));
                  }
      
                  // Performance
                  int count = 0;
      
                  values = new int[10];
                  for(int n = 0; n < values.Length; n++)
                  {
                      values[n] = n;
                  }
      
                  Stopwatch stopWatch = new Stopwatch();
                  stopWatch.Reset();
                  stopWatch.Start();
      
                  ForAllPermutation(values, (vals) =>
                  {
                      foreach(var v in vals)
                      {
                          count++;
                      }
                      return false;
                  });
      
                  stopWatch.Stop();
                  Debug.Print($"Non Linq {count} items in {stopWatch.ElapsedMilliseconds} millisecs");
      
                  count = 0;
                  stopWatch.Reset();
                  stopWatch.Start();
      
                  foreach (var vals in GetPermutations(values, values.Length))
                  {
                      foreach (var v in vals)
                      {
                          count++;
                      }
                  }
      
                  stopWatch.Stop();
                  Debug.Print($"Linq {count} items in {stopWatch.ElapsedMilliseconds} millisecs");
      
              }
          }
      }
      
        18
  •  1
  •   Maria Ines Parnisari    8 年前

    这是我的javascript解决方案(nodejs)。主要的想法是我们一次取一个元素,从字符串中“删除它”,改变其余的字符,并在前面插入元素。

    function perms (string) {
      if (string.length == 0) {
        return [];
      }
      if (string.length == 1) {
        return [string];
      }
      var list = [];
      for(var i = 0; i < string.length; i++) {
        var invariant = string[i];
        var rest = string.substr(0, i) + string.substr(i + 1);
        var newPerms = perms(rest);
        for (var j = 0; j < newPerms.length; j++) {
          list.push(invariant + newPerms[j]);
        }
      }
      return list;
    }
    
    module.exports = perms;
    

    以下是测试:

    require('should');
    var permutations = require('../src/perms');
    
    describe('permutations', function () {
      it('should permute ""', function () {
        permutations('').should.eql([]);
      })
    
      it('should permute "1"', function () {
        permutations('1').should.eql(['1']);
      })
    
      it('should permute "12"', function () {
        permutations('12').should.eql(['12', '21']);
      })
    
      it('should permute "123"', function () {
        var expected = ['123', '132', '321', '213', '231', '312'];
        var actual = permutations('123');
        expected.forEach(function (e) {
          actual.should.containEql(e);
        })
      })
    
      it('should permute "1234"', function () {
        // Wolfram Alpha FTW!
        var expected = ['1234', '1243', '1324', '1342', '1423', '1432', '2134', '2143', '2314', '2341', '2413', '2431', '3124', '3142', '3214', '3241', '3412', '3421', '4123', '4132'];
        var actual = permutations('1234');
        expected.forEach(function (e) {
          actual.should.containEql(e);
        })
      })
    })
    
        19
  •  1
  •   J D    7 年前

    下面是我能想到的最简单的解决方案:

    let rec distribute e = function
      | [] -> [[e]]
      | x::xs' as xs -> (e::xs)::[for xs in distribute e xs' -> x::xs]
    
    let permute xs = Seq.fold (fun ps x -> List.collect (distribute x) ps) [[]] xs
    

    这个 distribute 函数接受新元素 e 和一个 n -元素列表并返回 n+1 列出每个 e 插入到其他位置。例如,插入 10 在列表中四个可能的位置中的每一个 [1;2;3] :

    > distribute 10 [1..3];;
    val it : int list list =
      [[10; 1; 2; 3]; [1; 10; 2; 3]; [1; 2; 10; 3]; [1; 2; 3; 10]]
    

    这个 permute 函数在每个元素上依次折叠,分布在迄今为止累积的排列上,最终形成所有排列。例如,列表的6个排列 〔1;2;3〕 :

    > permute [1;2;3];;
    val it : int list list =
      [[3; 2; 1]; [2; 3; 1]; [2; 1; 3]; [3; 1; 2]; [1; 3; 2]; [1; 2; 3]]
    

    改变 fold 到A scan 为了保持中间累加器,可以了解如何一次生成元素排列:

    > Seq.scan (fun ps x -> List.collect (distribute x) ps) [[]] [1..3];;
    val it : seq<int list list> =
      seq
        [[[]]; [[1]]; [[2; 1]; [1; 2]];
         [[3; 2; 1]; [2; 3; 1]; [2; 1; 3]; [3; 1; 2]; [1; 3; 2]; [1; 2; 3]]]
    
        20
  •  1
  •   Val    7 年前

    列出字符串的排列。避免重复字符时的重复:

    using System;
    using System.Collections;
    
    class Permutation{
      static IEnumerable Permutations(string word){
        if (word == null || word.Length <= 1) {
          yield return word;
          yield break;
        }
    
        char firstChar = word[0];
        foreach( string subPermute in Permutations (word.Substring (1)) ) {
          int indexOfFirstChar = subPermute.IndexOf (firstChar);
          if (indexOfFirstChar == -1) indexOfFirstChar = subPermute.Length;
    
          for( int index = 0; index <= indexOfFirstChar; index++ )
            yield return subPermute.Insert (index, new string (firstChar, 1));
        }
      }
    
      static void Main(){
        foreach( var permutation in Permutations ("aab") )
          Console.WriteLine (permutation);
      }
    }
    
        21
  •  0
  •   user2674028    11 年前

    这是一个函数,它将递归地打印所有排列。

    public void Permutations(string input, StringBuilder sb)
        {
            if (sb.Length == input.Length)
            {
                Console.WriteLine(sb.ToString());
                return;
            }
    
            char[] inChar = input.ToCharArray();
    
            for (int i = 0; i < input.Length; i++)
            {
                if (!sb.ToString().Contains(inChar[i]))
                {
                    sb.Append(inChar[i]);
                    Permutations(input, sb);    
                    RemoveChar(sb, inChar[i]);
                }
            }
        }
    
    private bool RemoveChar(StringBuilder input, char toRemove)
        {
            int index = input.ToString().IndexOf(toRemove);
            if (index >= 0)
            {
                input.Remove(index, 1);
                return true;
            }
            return false;
        }
    
        22
  •  0
  •   Alexander Hitesh Bavaliya    10 年前
    class Permutation
    {
        public static List<string> Permutate(string seed, List<string> lstsList)
        {
            loopCounter = 0;
            // string s="\w{0,2}";
            var lstStrs = PermuateRecursive(seed);
    
            Trace.WriteLine("Loop counter :" + loopCounter);
            return lstStrs;
        }
    
        // Recursive function to find permutation
        private static List<string> PermuateRecursive(string seed)
        {
            List<string> lstStrs = new List<string>();
    
            if (seed.Length > 2)
            {
                for (int i = 0; i < seed.Length; i++)
                {
                    str = Swap(seed, 0, i);
    
                    PermuateRecursive(str.Substring(1, str.Length - 1)).ForEach(
                        s =>
                        {
                            lstStrs.Add(str[0] + s);
                            loopCounter++;
                        });
                    ;
                }
            }
            else
            {
                lstStrs.Add(seed);
                lstStrs.Add(Swap(seed, 0, 1));
            }
            return lstStrs;
        }
        //Loop counter variable to count total number of loop execution in various functions
        private static int loopCounter = 0;
    
        //Non recursive  version of permuation function
        public static List<string> Permutate(string seed)
        {
            loopCounter = 0;
            List<string> strList = new List<string>();
            strList.Add(seed);
            for (int i = 0; i < seed.Length; i++)
            {
                int count = strList.Count;
                for (int j = i + 1; j < seed.Length; j++)
                {
                    for (int k = 0; k < count; k++)
                    {
                        strList.Add(Swap(strList[k], i, j));
                        loopCounter++;
                    }
                }
            }
            Trace.WriteLine("Loop counter :" + loopCounter);
            return strList;
        }
    
        private static string Swap(string seed, int p, int p2)
        {
            Char[] chars = seed.ToCharArray();
            char temp = chars[p2];
            chars[p2] = chars[p];
            chars[p] = temp;
            return new string(chars);
        }
    }
    
        23
  •  0
  •   Peter Mortensen Aslan Kaya    10 年前

    这里有一个C答案,有点简单。

    public static void StringPermutationsDemo()
    {
        strBldr = new StringBuilder();
    
        string result = Permute("ABCD".ToCharArray(), 0);
        MessageBox.Show(result);
    }     
    
    static string Permute(char[] elementsList, int startIndex)
    {
        if (startIndex == elementsList.Length)
        {
            foreach (char element in elementsList)
            {
                strBldr.Append(" " + element);
            }
            strBldr.AppendLine("");
        }
        else
        {
            for (int tempIndex = startIndex; tempIndex <= elementsList.Length - 1; tempIndex++)
            {
                Swap(ref elementsList[startIndex], ref elementsList[tempIndex]);
    
                Permute(elementsList, (startIndex + 1));
    
                Swap(ref elementsList[startIndex], ref elementsList[tempIndex]);
            }
        }
    
        return strBldr.ToString();
    }
    
    static void Swap(ref char Char1, ref char Char2)
    {
        char tempElement = Char1;
        Char1 = Char2;
        Char2 = tempElement;
    }
    

    输出:

    1 2 3
    1 3 2
    
    2 1 3
    2 3 1
    
    3 2 1
    3 1 2
    
        24
  •  0
  •   Eduardo Teixeira    9 年前

    这是我的解决方案,我很容易理解

    class ClassicPermutationProblem
    {
        ClassicPermutationProblem() { }
    
        private static void PopulatePosition<T>(List<List<T>> finalList, List<T> list, List<T> temp, int position)
        {
             foreach (T element in list)
             {
                 List<T> currentTemp = temp.ToList();
                 if (!currentTemp.Contains(element))
                    currentTemp.Add(element);
                 else
                    continue;
    
                 if (position == list.Count)
                    finalList.Add(currentTemp);
                 else
                    PopulatePosition(finalList, list, currentTemp, position + 1);
            }
        }
    
        public static List<List<int>> GetPermutations(List<int> list)
        {
            List<List<int>> results = new List<List<int>>();
            PopulatePosition(results, list, new List<int>(), 1);
            return results;
         }
    }
    
    static void Main(string[] args)
    {
        List<List<int>> results = ClassicPermutationProblem.GetPermutations(new List<int>() { 1, 2, 3 });
    }
    
        25
  •  0
  •   Deepak Rohilla    8 年前

    下面是上述算法的另一个实现。

    public class Program
    {
        public static void Main(string[] args)
        {
            string str = "abcefgh";
            var astr = new Permutation().GenerateFor(str);
            Console.WriteLine(astr.Length);
            foreach(var a in astr)
            {
                Console.WriteLine(a);
            }
            //a.ForEach(Console.WriteLine);
        }
    }
    
    class Permutation
    {
        public string[] GenerateFor(string s)
        {  
    
            if(s.Length == 1)
            {
    
                return new []{s}; 
            }
    
            else if(s.Length == 2)
            {
    
                return new []{s[1].ToString()+s[0].ToString(),s[0].ToString()+s[1].ToString()};
    
            }
    
            var comb = new List<string>();
    
            foreach(var c in s)
            {
    
                string cStr = c.ToString();
    
                var sToProcess = s.Replace(cStr,"");
                if (!string.IsNullOrEmpty(sToProcess) && sToProcess.Length>0)
                {
                    var conCatStr = GenerateFor(sToProcess);
    
    
    
                    foreach(var a in conCatStr)
                    {
                        comb.Add(c.ToString()+a);
                    }
    
    
                }
            }
            return comb.ToArray();
    
        }
    }
    
        26
  •  0
  •   bolajiniy    7 年前
        //Generic C# Method
                private static List<T[]> GetPerms<T>(T[] input, int startIndex = 0)
                {
                    var perms = new List<T[]>();
    
                    var l = input.Length - 1;
    
                    if (l == startIndex)
                        perms.Add(input);
                    else
                    {
    
                        for (int i = startIndex; i <= l; i++)
                        {
                            var copy = input.ToArray(); //make copy
    
                            var temp = copy[startIndex];
    
                            copy[startIndex] = copy[i];
                            copy[i] = temp;
    
                            perms.AddRange(GetPerms(copy, startIndex + 1));
    
                        }
                    }
    
                    return perms;
                }
    
                //usages
                char[] charArray = new char[] { 'A', 'B', 'C' };
                var charPerms = GetPerms(charArray);
    
    
                string[] stringArray = new string[] { "Orange", "Mango", "Apple" };
                var stringPerms = GetPerms(stringArray);
    
    
                int[] intArray = new int[] { 1, 2, 3 };
                var intPerms = GetPerms(intArray);
    
        27
  •  -1
  •   CodeR    10 年前
        /// <summary>
        /// Print All the Permutations.
        /// </summary>
        /// <param name="inputStr">input string</param>
        /// <param name="strLength">length of the string</param>
        /// <param name="outputStr">output string</param>
        private void PrintAllPermutations(string inputStr, int strLength,string outputStr, int NumberOfChars)
        {
            //Means you have completed a permutation.
            if (outputStr.Length == NumberOfChars)
            {
                Console.WriteLine(outputStr);                
                return;
            }
    
            //For loop is used to print permutations starting with every character. first print all the permutations starting with a,then b, etc.
            for(int i=0 ; i< strLength; i++)
            {
                // Recursive call : for a string abc = a + perm(bc). b+ perm(ac) etc.
                PrintAllPermutations(inputStr.Remove(i, 1), strLength - 1, outputStr + inputStr.Substring(i, 1), 4);
            }
        }