Listing all permutations of a string/integer

后端 未结 29 1795
没有蜡笔的小新
没有蜡笔的小新 2020-11-22 00:44

A common task in programming interviews (not from my experience of interviews though) is to take a string or an integer and list every possible permutation.

Is there

相关标签:
29条回答
  • 2020-11-22 01:14

    First of all: it smells like recursion of course!

    Since you also wanted to know the principle, I did my best to explain it human language. I think recursion is very easy most of the times. You only have to grasp two steps:

    1. The first step
    2. All the other steps (all with the same logic)

    In human language:

    In short:

    1. The permutation of 1 element is one element.
    2. The permutation of a set of elements is a list each of the elements, concatenated with every permutation of the other elements.

    Example:

    If the set just has one element -->
    return it.
    perm(a) -> a

    If the set has two characters: for each element in it: return the element, with the permutation of the rest of the elements added, like so:

    perm(ab) ->

    a + perm(b) -> ab

    b + perm(a) -> ba

    Further: for each character in the set: return a character, concatenated with a permutation of > the rest of the set

    perm(abc) ->

    a + perm(bc) --> abc, acb

    b + perm(ac) --> bac, bca

    c + perm(ab) --> cab, cba

    perm(abc...z) -->

    a + perm(...), b + perm(....)
    ....

    I found the pseudocode on 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#

    OK, and something more elaborate (and since it is tagged c #), from http://radio.weblogs.com/0111551/stories/2002/10/14/permutations.html : Rather lengthy, but I decided to copy it anyway, so the post is not dependent on the original.

    The function takes a string of characters, and writes down every possible permutation of that exact string, so for example, if "ABC" has been supplied, should spill out:

    ABC, ACB, BAC, BCA, CAB, CBA.

    Code:

    class Program
    {
        private static void Swap(ref char a, ref char b)
        {
            if (a == b) return;
    
            var temp = a;
            a = b;
            b = temp;
        }
    
        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);
        }
    }
    
    0 讨论(0)
  • 2020-11-22 01:16

    It's just two lines of code if LINQ is allowed to use. Please see my answer here.

    EDIT

    Here is my generic function which can return all the permutations (not combinations) from a list of 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 }));
    }
    

    Example:

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

    Output - a list of integer-lists:

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

    As this function uses LINQ so it requires .net 3.5 or higher.

    0 讨论(0)
  • 2020-11-22 01:16
    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]);
      }
    }
    

    You can write your swap function to swap characters.
    This is to be called as permute(string, 0);

    0 讨论(0)
  • 2020-11-22 01:16

    Here is the function which will print all permutaion. This function implements logic Explained by 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();
    
        }
    
    0 讨论(0)
  • 2020-11-22 01:19

    This is my solution which it is easy for me to understand

    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 });
    }
    
    0 讨论(0)
  • 2020-11-22 01:19

    If performance and memory is an issue, I suggest this very efficient implementation. According to Heap's algorithm in Wikipedia, it should be the fastest. Hope it will fits your need :-) !

    Just as comparison of this with a Linq implementation for 10! (code included):

    • This: 36288000 items in 235 millisecs
    • Linq: 36288000 items in 50051 millisecs

      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");
      
              }
          }
      }
      
    0 讨论(0)
提交回复
热议问题