С учетом строки найдите другую строку, содержащую все комбинации входной строки.
Пример:
Если входная строка = "23", то ее комбинации будут ["22", "23", "32", "33"],
Одна из строк, содержащих все вышеперечисленные комбинации, будет "22233233", но это не было бы самым коротким. Самый короткий - "22332".
Алгоритм должен быть достаточно общим для работы с входной строкой любого размера. (Предположим, что вход не слишком велик, и выход останется под нормальным размером int/string/jvm и т.д. Также предположим, что входная строка будет иметь буквенно-цифровые символы только на английском языке)
Я пробовал следующий алгоритм, но он, похоже, не работает:
1) Найдите все комбинации строки = ["22", "23", "32", "33"]
2) Создайте префиксную карту [2: {22, 23}, 3: {32, 33}]
3) Начните с любой комбинации и суффикса поиска в префиксной карте.
Пример: Начните с 22, его суффикс равен 2 Из префикс-карты значения, соответствующие 2, равны 22 и 23. Выберите одно из слов здесь, которое не является текущим выбранным словом, поэтому оно даст 23
4) Добавить выбранный суффикс слова в текущую строку (это дает 223)
5) Повторите. Итак, я получу 223 суффикса = 3 Из префиксной карты, 3: {32, 33} Выберите любой, скажем, 32 Присоединитесь к текущей строке, чтобы получить 2232
6) Если ничего другого не найдено, добавьте текущую строку. Это дает 223233
Однако ответ должен быть 22332, поскольку это самый короткий.
Вот полный код, который я написал до сих пор:
public class TextContainingAllPermutations
{
static String input = "ABC";
public static void main (String args[])
{
int suffixLen = input.length()-1;
Set<String> combinations = getCombinations();
while (suffixLen > 0 && combinations.size() > 1)
{
Map<String, List<String>> suffixToWords = getPrefixMap(combinations, suffixLen);
String someWordsString = combinations.iterator().next();
combinations.remove(someWordsString);
Set<String> combinations2 = new HashSet<String>();
while (combinations.size() > 0)
{
String suffix = someWordsString.substring(someWordsString.length()-suffixLen);
List<String> words = suffixToWords.get(suffix);
if (words == null || words.size()==0)
{
combinations2.add(someWordsString);
System.out.println (someWordsString);
if (combinations.size() == 0)
break;
someWordsString = combinations.iterator().next();
combinations.remove(someWordsString);
}
else
{
String w = words.get(words.size()-1);
words.remove(words.size()-1);
combinations.remove(w);
if (someWordsString.indexOf(w) == -1)
someWordsString += w.charAt(w.length()-1); // append last char
}
}
combinations2.add(someWordsString);
System.out.println (someWordsString);
combinations = combinations2;
suffixLen--;
}
}
private static Map<String, List<String>> getPrefixMap(Set<String> combinations, int suffixLen)
{
Map<String, List<String>> suffixToWords = new HashMap<String, List<String>>();
for (String s: combinations)
{
String suffix = s.substring(0,suffixLen);
if (!suffixToWords.containsKey(suffix))
{
suffixToWords.put(suffix, new ArrayList<String>());
}
suffixToWords.get(suffix).add(s);
}
return suffixToWords;
}
static Set<String> getCombinations()
{
char[] inputChars = input.toCharArray();
int N = (int)Math.pow(input.length(), input.length());
Set<String> combinations = new HashSet<String>(N);
for (int i=0; i<N; i++)
{
char[] binary = padZeroes(Integer.toString(i, input.length())).toCharArray();
String combination = "";
for (int j=0; j<inputChars.length; j++)
{
char c = binary[j];
int index = c - '0';
char inputChar = inputChars[index];
combination = inputChar + combination;
}
System.out.println (new String(binary) + " = " + combination);
combinations.add(combination);
}
return combinations;
}
private static String padZeroes(String s)
{
int j = input.length()-s.length();
for (int i=0; i<j; i++)
s = '0' + s;
return s;
}
}
Это не проблема домашних заданий.
То, что вы ищете, - это в основном последовательность Де Бройна. Последовательность B(k,n)
Брейна B(k,n)
является циклической последовательностью, которая содержит все возможные подпоследовательности длины n
из множества k
символов, каждый из которых появляется ровно один раз. Длина последовательности точно равна k n
.
Минимальная нециклическая последовательность может быть получена путем разбиения цикла в любой точке и последующего копирования первых n-1
символов в конец, создавая последовательность длины k n + n - 1
, которая, очевидно, минимальна.
Существует множество методов генерации последовательности De Bruijn. Самый простой способ описания состоит в том, что последовательность де Брейна состоит из конкатенации всех слов Линдона над алфавитом, длина которого делит n
в лексикографическом порядке. (Слово Линдона - это последовательность, которая лексикографически предшествует любому вращению самого себя. Отсюда следует, что слово Линдона является апериодическим.)
Существует простой алгоритм для генерации слов Линдона максимальной длины n
над алфавитом в лексикографическом порядке:
n
(отбрасывая лишние символы из последнего повторения, если необходимо), а затем "увеличивая" слово: Чтобы сделать последовательность Де Брейна порядка n
, мы создаем указанную выше последовательность слов Линдона, но мы сохраняем только те, длина которых делит n
. Так как "почти все" слов Линдона максимальной длины n
на самом деле имеют длину n
, алгоритм можно считать O (1) на символ, или O(k n)
для полной последовательности.
В конкретном случае, заданном вопросом, k == n
.