Оптимальный алгоритм генерации всех комбинаций (порядок букв имеет значение) слова

Я ищу алгоритм (оптимальный) для генерации всех возможных комбинаций слова.

Например:

Со словом love будет выведено следующее:

Сгенерированные слова: 24 elov elvo eolv eovl evlo evol leov levo loev love lveo lvoe oelv oevl olev olve ovel ovle velo veol vleo vloe voel vole

Учитывая слово bell (обратите внимание на повторяющийся l), будет выведено следующее:

Сгенерированные слова: 12 bell blel blle ebll elbl ellb lbel lble lebl lelb llbe lleb

У меня есть свой алгоритм генерации всех комбинаций заданного слова. Я в основном реализую комбинированное дерево. Это намного более всеобъемлюще, но требует много места и времени.


person Lynnell Neri    schedule 17.07.2013    source источник
comment
Что такое дерево комбинаций?Рекурсивная генерация комбинаций?   -  person Aravind    schedule 17.07.2013
comment
Может быть, вы хотите отсортировать слово лексикографически и применить какую-нибудь функцию nextWord, пока это возможно?   -  person Herokiller    schedule 17.07.2013
comment
Я думаю, что более подходящим термином является перестановка мультимножества. en.wikipedia.org/wiki/Permutation   -  person rliu    schedule 17.07.2013
comment
Этот вопрос кажется многообещающим: stackoverflow.com/questions/3467914/. Обратите внимание, что он генерирует не все перестановки, а генерирует их с точностью до циклического изоморфизма (‹- это я придумал). Итак, после того, как у вас есть все эти различные циклические схемы, вам придется вращать их, чтобы сгенерировать перестановки. Но этот дополнительный шаг быстрый (линейный). Итак, если алгоритм Савады быстрый, то и весь алгоритм будет быстрым.   -  person rliu    schedule 17.07.2013


Ответы (3)


  1. Возьмите общее количество букв в слове n и найдите n!.
  2. Подсчитайте количество вхождений каждой буквы. Каждую букву, которая повторяется более одного раза, разделите на (количество повторений)!

Пример: «банан»

2 н, 3 а, всего 6 букв

Ответ = 6!/(2!*3!) = 60

person enderx1x    schedule 17.07.2013

Можно генерировать перестановки (исключая ограничение дублирования), для каждого символа заменяя этот символ первым символом и рекурсивно исключая первый символ.

Теперь, если мы хотим исключить дубликаты, нам просто нужно убедиться, что мы не помещаем один и тот же символ в первую позицию дважды. Это можно сделать, отсортировав символы (чтобы повторяющиеся символы находились рядом друг с другом) и пропустив любой символ, который совпадает с предыдущим или совпадает с символом в целевой позиции.

Код Java: (полученный из базового генератора перестановок)

import java.util.Arrays;
import java.util.Scanner;

public class NewMain
{
   public static void main(String[] args)
   {
      Scanner sc = new Scanner(System.in);
      System.out.println("Enter the string:");
      String s = sc.nextLine();
      char[] c = s.toCharArray();
      Arrays.sort(c);

      System.out.println("Here are all the permutations:");
      NewMain.c = c;
      count = 0;
      permutation(0);
      System.out.println("Number of permutations = " + count);
   }

   static char[] c;
   static int count;

   static void swap(int pos1, int pos2)
   {
      char temp = c[pos1];
      c[pos1] = c[pos2];
      c[pos2] = temp;
   }

   public static void permutation(int start)
   {
      if (start == c.length)
      {
         System.out.println(c);
         count++;
      }

      for (int i = start; i < c.length; i++)
      {
         if (i == start || (c[i] != c[i-1] && c[i] != c[start]))
         {
            swap(start, i);
            permutation(start + 1);
            swap(start, i);
         }
      }
   }
}

Тест.

Теперь это все еще не особенно эффективно, если есть слишком много повторяющихся символов. Один из способов, который я могу придумать, чтобы улучшить это, - это иметь счетчик для каждого символа (возможно, в форме связанного списка (связанный список счетчиков), чтобы мы могли быстро удалить счетчики, которые достигли 0, и вставить их обратно после этого) и, как и выше, мы генерируем символы слева направо, пропуская дубликаты, обрабатывая каждый счет только один раз на каждом рекурсивном шаге.

person Bernhard Barker    schedule 17.07.2013

Спустя долгое время я наконец получил ответ на свой вопрос. Я использовал PHP в качестве языка программирования (потому что это мой выбор, а не что-то еще) и я использовал Pear Package: Math Комбинаторика.

person Lynnell Neri    schedule 16.02.2015