Listing all permutations of a string/integer

后端 未结 29 1984
没有蜡笔的小新
没有蜡笔的小新 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: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
      {
          /// 
          /// 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
          /// 
          public static class Permutations
          {
              /// 
              /// Heap's algorithm to find all pmermutations. Non recursive, more efficient.
              /// 
              /// Items to permute in each possible ways
              /// 
              /// Return true if cancelled 
              public static bool ForAllPermutation(T[] items, Func 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;
              }
      
              /// 
              /// This function is to show a linq way but is far less efficient
              /// 
              /// 
              /// 
              /// 
              /// 
              static IEnumerable> GetPermutations(IEnumerable 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 }));
              }
      
              /// 
              /// Swap 2 elements of same type
              /// 
              /// 
              /// 
              /// 
              [MethodImpl(MethodImplOptions.AggressiveInlining)]
              static void Swap(ref T a, ref T b)
              {
                  T temp = a;
                  a = b;
                  b = temp;
              }
      
              /// 
              /// Func to show how to call. It does a little test for an array of 4 items.
              /// 
              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");
      
              }
          }
      }
      

提交回复
热议问题