Моему другу на собеседовании на должность разработчика программного обеспечения был задан следующий вопрос:
Учитывая две строки, s1
и s2
как вы будете проверять, s1
является ли повернутая версия s2
?
Пример:
Если s1 = "stackoverflow"
затем следующие некоторые из его повернутых версий:
"tackoverflows"
"ackoverflowst"
"overflowstack"
где , как "stackoverflwo"
это не повернутая версия.
Ответ, который он дал, был:
Возьмите
s2
и найдите самый длинный префикс, который является подстрокойs1
, которая даст вам точку поворота. Как только вы найдете эту точку, прервитесьs2
в этой точке, чтобы получить,s2a
аs2b
затем просто проверьте, еслиconcatenate(s2a,s2b) == s1
Это выглядит как хорошее решение для меня и моего друга. Но интервьюер думал иначе. Он попросил более простое решение. Пожалуйста, помогите мне, расскажите, как бы вы это сделали Java/C/C++
?
Заранее спасибо.
Ответы:
Сначала убедитесь , что
s1
иs2
имеют одинаковую длину. Затем проверьте,s2
является ли подстрокаs1
объединенной сs1
:В Java:
источник
(s1+s1).contains(s2)
в Java.s1+s1
. Ясно, что все его подстроки с размерамиs1.length
являются вращениямиs1
по построению. Следовательно, любая строка размера,s1.length
которая является подстрокой,s1+s1
должна быть вращениемs1
.Конечно, лучшим ответом было бы: «Ну, я бы попросил сообщество stackoverflow и, вероятно, получило бы как минимум 4 действительно хороших ответа в течение 5 минут». Мозги хороши и все такое, но я бы больше ценил того, кто знает, как работать с другими, чтобы найти решение.
источник
Еще один пример с питоном (основанный на ответе):
источник
s2
а неs1
слишком ... потом понял, что отношение было симметричным в любом случае.in
оператор не использует алгоритм O (n)?s1 in s2
оптимизирован. См. Effbot.org/zone/stringlib.htm для описания алгоритма. Похоже, Google указывает, что в Java нет быстрого поиска строк (см., Например, johannburkard.de/software/stringsearch ), хотя я сомневаюсь, что это что-то сломает, если они его изменят .Поскольку другие представили квадратичное решение для временной сложности в худшем случае, я бы добавил линейное решение (на основе алгоритма KMP ):
рабочий пример
источник
РЕДАКТИРОВАТЬ: Принятый ответ явно более элегантный и эффективный, чем этот, если вы его заметили. Я оставил этот ответ как то, что сделал бы, если бы не думал удвоить исходную строку.
Я бы просто перебор. Сначала проверьте длину, а затем попробуйте все возможные смещения вращения. Если ни один из них не сработает, верните false - если любой из них сработает, немедленно верните true.
Нет особой необходимости объединять - просто используйте указатели (C) или индексы (Java) и идите вместе, по одному в каждой строке - начиная с начала одной строки и текущего смещения вращения кандидата во второй строке, и оборачивая при необходимости , Проверьте равенство символов в каждой точке строки. Если вы доберетесь до конца первой строки, все готово.
Вероятно, объединить его будет так же легко, хотя, возможно, и менее эффективно, по крайней мере в Java.
источник
Вот один из них, использующий регулярное выражение просто для удовольствия:
Вы можете сделать это немного проще, если вы можете использовать специальный символ-разделитель, который гарантированно не будет находиться ни в одной из строк.
Вы также можете использовать lookbehind с конечным повторением:
источник
Воу, воу ... почему все так взволнованы
O(n^2)
ответом? Я уверен, что мы можем добиться большего успеха здесь. Ответ выше включает в себяO(n)
операцию вO(n)
цикле (вызов substring / indexOf). Даже с более эффективным алгоритмом поиска; скажемBoyer-Moore
илиKMP
, худший случай ещеO(n^2)
с дубликатами.O(n)
Рандомизированное Ответ прост; взять хеш (например, отпечаток Рабина), который поддерживаетO(1)
скользящее окно; хеш-строка 1, затем хеш-строка 2 и приступаем к перемещению окна для хеш-функции 1 вокруг строки и проверяем, не сталкиваются ли хеш-функции.Если мы представим, что худший случай - это что-то вроде «сканирования двух нитей ДНК», то вероятность столкновения возрастает, и это, вероятно, вырождается в нечто вроде
O(n^(1+e))
или что-то в этом роде (только догадываясь здесь).Наконец, есть детерминированное
O(nlogn)
решение с очень большой константой снаружи. По сути, идея состоит в том, чтобы взять свертку из двух строк. Максимальным значением свертки будет разность вращения (если они вращаются); Н.O(n)
проверка подтверждает. Приятно то, что если есть два равных максимальных значения, то оба они также являются допустимыми решениями. Вы можете сделать свертку с двумя FFT и точечным продуктом, и iFFT, такnlogn + nlogn + n + nlogn + n == O(nlogn)
.Поскольку вы не можете заполнить нулями и не можете гарантировать, что строки имеют длину 2 ^ n, FFT не будут быстрыми; они будут медленными, все еще
O(nlogn)
но с гораздо большей константой, чем алгоритм CT.Все это говорит о том, что я абсолютно на 100% уверен, что здесь есть детерминистическое
O(n)
решение, но проклят, если смогу его найти.источник
%stringsize
) гарантированно будет иметь линейное время.Кулак, убедитесь, что 2 строки имеют одинаковую длину. Затем в C вы можете сделать это с помощью простой итерации указателя.
источник
Вот
O(n)
и на месте Алгоритм. Он использует<
оператор для элементов строк. Это не мое, конечно. Я взял его отсюда (Сайт на польском языке. Я однажды наткнулся на него и не смог найти что-то подобное сейчас на английском, поэтому я покажу, что у меня есть :)).источник
Я думаю, что лучше сделать это в
Java
:В Perl я бы сделал:
или даже лучше, используя функцию индекса вместо регулярного выражения:
источник
\Q
в/\Q$string2/
.\Q
цитирует любые специальные символы в$string2
. Без него.
будет считаться поворот любой 1-символьной строки.Не уверен, что это самый эффективный метод, но он может быть относительно интересным : преобразование Барроуза-Уилера . Согласно статье WP, все чередования входов дают одинаковый результат. Для таких приложений, как сжатие, это нежелательно, поэтому указывается исходное вращение (например, индексом; см. Статью). Но для простого независимого от вращения сравнения это звучит идеально. Конечно, это не обязательно идеально эффективно!
источник
Возьмите каждый символ в качестве амплитуды и выполните дискретное преобразование Фурье для них. Если они отличаются только вращением, частотные спектры будут одинаковыми с точностью до погрешности округления. Конечно, это неэффективно, если длина не является степенью 2, поэтому вы можете сделать БПФ :-)
источник
Никто еще не предложил подход по модулю, так что вот один:
Вывод:
[РЕДАКТИРОВАТЬ: 2010-04-12]
Петр заметил недостаток в моем коде выше. Это ошибки, когда первый символ в строке встречается дважды или более. Например,
stackoverflow
проверка наowstackoverflow
результат привела к ложному результату, когда оно должно быть истинным.Спасибо, Петр, за обнаружение ошибки.
Теперь исправленный код:
Вот вывод:
Вот лямбда-подход:
Вот вывод лямбда-подхода:
источник
Поскольку никто не дал решение C ++. вот это оно:
источник
Простой трюк поворота указателя в Opera работает, но он крайне неэффективен в худшем случае во время выполнения. Просто представьте строку со множеством длинных повторяющихся серий символов, а именно:
«Цикл, пока не будет несоответствия, затем увеличьте его на единицу и попробуйте снова» - это ужасный подход в вычислительном отношении.
Чтобы доказать, что вы можете использовать подход конкатенации в простом C без особых усилий, вот мое решение:
Это линейно во время выполнения за счет использования O (n) памяти в накладных расходах.
(Обратите внимание, что реализация strstr () зависит от платформы, но, если она не работает, ее всегда можно заменить более быстрой альтернативой, такой как алгоритм Бойера-Мура)
источник
strstr()
в O (N + M)? Кроме того, если стандарт (или что-либо еще) не гарантирует вам линейное время выполненияstrstr()
, вы не можете утверждать, что весь алгоритм имеет линейную временную конкуренцию.s1SelfConcat
: только с C9x C допускает переменные размеры массива (хотя GCC допускает это намного дольше), и вы столкнетесь с проблемами при выделении больших строк в стеке. Йосеф Крейнин написал очень забавный пост в блоге об этой проблеме. Кроме того, ваше решение по-прежнему квадратичное время с Бойер-Мур; ты хочешь КМП.C #:
источник
Мне нравится ответ THE, который проверяет, является ли s2 подстрокой s1, объединенной с s1.
Я хотел добавить оптимизацию, которая не теряет своей элегантности.
Вместо объединения строк вы можете использовать представление соединения (я не знаю для другого языка, но для C ++ Boost.Range предоставляют такие виды представлений).
Поскольку проверка того, является ли строка подстрокой другой, имеет линейную среднюю сложность (сложность наихудшего случая является квадратичной), эта оптимизация должна повысить скорость в среднем в 2 раза.
источник
Чистый Java-ответ (без проверки нуля)
источник
А сейчас нечто соверешнно другое.
Если вам нужен действительно быстрый ответ в ограниченном контексте, когда строки не вращаются друг относительно друга
Согласен, он может потерпеть неудачу, но очень быстро сказать, если строки не совпадают и если они совпадают, вы все равно можете использовать другой алгоритм, такой как конкатенация строк, для проверки.
источник
Другое решение Руби на основе в ответ:
источник
Это очень легко написать на PHP, используя
strlen
иstrpos
функции:Я не знаю, что
strpos
использует внутренне, но если это использует KMP, это будет линейно во времени.источник
Переверните одну из строк. Возьмите БПФ обоих (рассматривая их как простые последовательности целых чисел). Умножьте результаты вместе по точкам. Преобразование обратно с использованием обратного БПФ. Результат будет иметь один пик, если струны являются вращениями друг друга - положение пика будет указывать на то, насколько они повернуты друг относительно друга.
источник
Почему не как то так?
Конечно, вы можете написать свою собственную функцию IndexOf (); Я не уверен, использует ли .NET наивный или более быстрый способ.
Наивный:
Быстрее:
Редактировать: у меня могут быть некоторые личные проблемы; не хочется проверять ;)
источник
Я бы сделал это в Perl :
источник
источник
Регистрация
string1
сstring2
и использовать алгоритм КМП для проверкиstring2
присутствует во вновь сформированной строки. Потому что временная сложность КМП меньше, чемsubstr
.источник