О вопросе ... Он никогда не просил оптимального решения, и эти типы вопросов не хотят этого. Вам нужно написать алгоритм общего назначения для решения этой проблемы, и поиск методом «грубой силы», чтобы найти лучшее решение, невозможен для строк, длина которых может быть мегабайтом. Также я поздно заметил, что гарантированно будет одинаковое количество нулей и единиц, но я думаю, что более интересно работать с общим случаем, когда могут быть разные числа нулей и единиц. На самом деле не гарантируется, что будет решение в каждом случае, если длина входной строки меньше 7, даже в том случае, если у вас 2 0 и 2 1.
Размер 3: только одна цифра, поэтому она сортируется по определению (UU0 UU1 0UU 1UU)
Размер 4: Нет способа изменить порядок. Ходов нет, если UU находится посередине, и только замена обеих цифр, если они заканчиваются (1UU0 без ходов, UU10-> 10UU-> UU10 и т. Д.)
Размер 5: UU в середине может перемещаться только на дальний конец и не изменять порядок 0 и 1 (1UU10-> 110UU). UU на конце может перемещаться в середину и не изменять порядок, а только возвращаться к тому же концу, поэтому его бесполезно (UU110-> 11UU0-> UU110). Единственный способ изменить цифры - это если UU находится в конце и поменяться с противоположным концом. (UUABC-> BCAUU или ABCUU-> UUCAB). Это означает, что если UU находится в позициях 0 или 2, он может решить, находится ли 0 в середине (UU101-> 011UU или UU100-> 001UU), и если UU находится в позициях 1 или 3, он может решить, находится ли 1 в середине ( 010UU-> UU001 или 110UU-> UU011). Все остальное уже решено или неразрешимо. Если нам нужно разобраться с этим делом, я бы сказал, жестко закодировать его. Если отсортировано, вернуть результат (без ходов). Если UU где-то посередине, переместите его до конца. Поменяйте местами с конца на другой конец, и это единственно возможный обмен, независимо от того, отсортирован он сейчас или нет.
Размер 6: Теперь мы получаем позицию, в которой мы можем указать строку в соответствии с правилами, где мы можем делать ходы, но где не может быть решения. В этом и заключается проблема любого алгоритма, потому что я думаю, что условием любого решения должно быть то, что оно сообщит вам, если оно не может быть решено. Например, 0010, 0100, 1000, 1011, 1100, 1101 и 1110 могут быть решены независимо от того, где находится UU, а наихудшие случаи требуют 4 хода для решения. 0101 и 1010 могут быть решены, только если UU находится в нечетном положении. 0110 и 1001 могут быть решены, только если UU находится в четном положении (либо в конце, либо в середине).
Я думаю, что лучшим способом будет что-то вроде следующего, но я еще не написал это. Во-первых, убедитесь, что вы ставите «1» в конце списка. Если конец в настоящий момент равен 0, переместите UU в конец, затем переместите его в последнюю позицию «1» - 1. После этого вы постоянно перемещаете UU к первому «1», а затем к первому «0» после нового UU. Это переместит все 0 в начало списка. Я видел аналогичный ответ с другой стороны, но он не учитывал окончательный характер с обеих сторон. Это может привести к проблемам с небольшими значениями (например, 001UU01, невозможно перейти к первому 1, перейти к концу, 00101UU позволяет нам перейти к началу, но оставляет 0 в конце 00UU110).
Я предполагаю, что вы можете жестко запрограммировать такие особые случаи. Я думаю, что может быть лучший алгоритм, хотя. Например, вы можете использовать первые два символа как временную переменную подкачки. Вы бы поместили UU тут же, а затем выполняли комбинации операций над другими, чтобы оставить UY в начале. Например, UUABCDE может поменять AB с CD или DE или BC с DE (BCAUUDE-> BCADEUU-> UUADEBC).
Другой возможной вещью было бы рассматривать символы как два блока из двух битов base-3
0101UU0101 будет отображаться как 11C11 или 3593. Может также быть что-то вроде комбинации жестко закодированных свопов. Например, если вы когда-либо видите 11UU, переместите UU влево 2. Если вы когда-либо увидите UU00, переместите UU вправо на два. Если вы видите UU100 или UU101, переместите UU вправо 2, чтобы получить 001UU или 011UU.
Может быть, другой возможностью был бы некоторый алгоритм для перемещения нулей влево от центра и 1 секунд вправо от центра (если дано, что есть одинаковое количество нулей и 1сек.
Может быть, было бы лучше поработатьдля структуры, которая содержит только 0 и 1 с позицией для UU.
Может быть, лучше посмотреть на результирующее условие, позволяя UU находиться где-нибудь в строке, эти условия ДОЛЖНЫ быть выполнены: нет 0 с после длины/ 2 No 1s before (Длина / 2-1)
Возможно, есть более общие правила, например, действительно полезно поменять UU на 10 в этом случае на 10111UU0, потому что теперь 0 стоит после UU иэто позволит вам переместить новый 00 обратно туда, где было 10 (10111UU0-> UU111100-> 001111UU).
В любом случае, вот код грубой силы в C #. Входные данные представляют собой строку и пустой словарь.Он заполняет словарь каждой возможной результирующей строкой в качестве ключей и списком кратчайших шагов, чтобы получить его в качестве значения:
Вызов:
m_Steps = new Dictionary<string, List<string>>();
DoSort("UU1010011101", new List<string>);
Включает DoTests ()который вызывает DoSort для каждой возможной строки с заданным количеством цифр (не включая UU):
Dictionary<string, List<string>> m_Steps = new Dictionary<string, List<string>>();
public void DoStep(string state, List<string> moves) {
if (m_Steps.ContainsKey(state) && m_Steps[state].Count <= moves.Count + 1) // have better already
return;
// we have a better (or new) solution to get to this state, so set it to the moves we used to get here
List<string> newMoves = new List<string>(moves);
newMoves.Add(state);
m_Steps[state] = newMoves;
// if the state is a valid solution, stop here
if (state.IndexOf('1') > state.LastIndexOf('0'))
return;
// try all moves
int upos = state.IndexOf('U');
for (int i = 0; i < state.Length - 1; i++) {
// need to be at least 2 before or 2 after the UU position (00UU11 upos is 2, so can only move to 0 or 4)
if (i > upos - 2 && i < upos + 2)
continue;
char[] chars = state.ToCharArray();
chars[upos] = chars[i];
chars[upos + 1] = chars[i + 1];
chars[i] = chars[i + 1] = 'U';
DoStep(new String(chars), newMoves);
}
}
public void DoTests(int digits) { // try all combinations
char[] chars = new char[digits + 2];
for (int value = 0; value < (2 << digits); value++) {
for (int uupos = 0; uupos < chars.Length - 1; uupos++) {
for (int i = 0; i < chars.Length; i++) {
if (i < uupos)
chars[i] = ((value >> i) & 0x01) > 0 ? '1' : '0';
else if (i > uupos + 1)
chars[i] = ((value >> (i - 2)) & 0x01) > 0 ? '1' : '0';
else
chars[i] = 'U';
}
m_Steps = new Dictionary<string, List<string>>();
DoSort(new string(chars), new List<string>);
foreach (string key in m_Steps.AllKeys))
if (key.IndexOf('1') > key.LastIndexOf('0')) { // winner
foreach (string step in m_Steps[key])
Console.Write("{0}\t", step);
Console.WriteLine();
}
}
}
}