Таким образом, я сталкивался с различными проблемами для просмотра предстоящих собеседований, и один из них, с которым я столкнулся, определяет, являются ли две строки вращением друг друга. Очевидно, что я едва ли первый человек, решивший эту проблему. Фактически, я обнаружил, что моя идея для решения этого похоже на подход, использованный в этом вопросе.
Полное раскрытие: у меня есть связанный вопрос в Math SE, который фокусируется на свойствах с более математической точки зрения (хотя стоит отметить, что способ, которым я пытался формулировать идеи, стоящие за этим, в конечном итоге являются неправильными по причинам, которые объясняются там).
Здесь идея (и это похоже на подход, использованный в связанном вопросе): предположим, что у вас есть строка abcd
и вращение cdab
. Очевидно, что оба cd
и ab
являются подстроками cdab
, но если вы объедините их вместе, вы получите abcd
.
В принципе, поворот просто влечет за собой перемещение подстроки от конца строки до начала (например, мы построили cdab
из abcd
, перемещая cd
от конца строки до начала строки).
Я придумал подход, который работает в очень ограниченном случае (если обе подстроки состоят из последовательных букв, как в примере), но в противном случае он не работает (и я приведу пример прохождения и сбоя случаев и вводов/выходов ниже кода). Я пытаюсь выяснить, возможно ли (или даже стоит) попытаться исправить его для работы в общем случае.
public bool AreRotations(string a, string b)
{
if (a == null)
throw new ArgumentNullException("a");
else if (b == null)
throw new ArgumentNullException("b");
else if (a.Trim().Length == 0)
throw new ArgumentException("a is empty or consists only of whitespace");
else if (b.Trim().Length == 0)
throw new ArgumentException("b is empty or consists only of whitespace");
// Obviously, if the strings are of different lengths, they can't possibly be rotations of each other
if (a.Length != b.Length)
return false;
int[] rotationLengths = new int[a.Length];
/* For rotations of length -2, -2, -2, 2, 2, 2, the distinct rotation lengths are -2, 2
*
* In the example I give below of a non-working input, this contains -16, -23, 16, 23
*
* On the face of it, that would seem like a useful pattern, but it seems like this
* could quickly get out of hand as I discover more edge cases
*/
List<int> distinctRotationLengths = new List<int>();
for (int i = 0; i < a.Length; i++)
{
rotationLengths[i] = a[i] - b[i];
if (i == 0)
distinctRotationLengths.Add(rotationLengths[0]);
else if (rotationLengths[i] != rotationLengths[i - 1])
{
distinctRotationLengths.Add(rotationLengths[i]);
}
}
return distinctRotationLengths.Count == 2;
}
И теперь для выборки входов/выходов:
StringIsRotation rot = new StringIsRotation();
// This is the case that doesn't work right - it gives "false" instead of "true"
bool success = rot.AreRotations("acqz", "qzac");
// True
success = rot.AreRotations("abcdef", "cdefab");
// True
success = rot.AreRotations("ablm", "lmab");
// False, but should be true - this is another illustration of the bug
success = rot.AreRotations("baby", "byba");
// True
success = rot.AreRotations("abcdef", "defabc");
//True
success = rot.AreRotations("abcd", "cdab");
// True
success = rot.AreRotations("abc", "cab");
// False
success = rot.AreRotations("abcd", "acbd");
// This is an odd situation - right now it returns "false" but you could
// argue about whether that correct
success = rot.AreRotations("abcd", "abcd");
Возможно ли/целесообразно спасти этот подход и все равно быть O (n), или я должен просто пойти с одним из подходов, описанных в сообщении, которое я связал? (Обратите внимание, что это не производственный код или домашнее задание, это чисто для моего собственного обучения).
Изменить: Для дальнейшего пояснения, основанного на комментариях, здесь есть два вопроса: во-первых, этот алгоритм можно устранить? Во-вторых, стоит ли его исправлять (или я просто попробую другой подход, как описано в ответах или другом вопросе, к которому я привязался)? Я думал о нескольких возможных исправлениях, но все они касались либо неэлегантного аргумента в отношении конкретного случая, либо создания этого алгоритма O (n ^ 2), оба из которых в первую очередь убьют точку алгоритма.