Интервью: проверьте, является ли одна строка вращением другой строки

224

Другу моему был задан следующий вопрос сегодня в интервью для должности разработчика программного обеспечения:

Учитывая две строки s1 и s2, как вы проверите, является ли s1 версией s2 <

Пример:

Если s1 = "stackoverflow", то некоторые из его повернутых версий:

"tackoverflows"
"ackoverflowst"
"overflowstack"

где "stackoverflwo" не развернутая версия.

Ответ, который он дал, был:

Возьмите s2 и найдите самый длинный префикс, который является подстрокой s1, которая даст вам точку поворота. Как только вы найдете эту точку, сломайте s2 в этой точке, чтобы получить s2a и s2b, а затем просто проверьте, если concatenate(s2a,s2b) == s1

Это похоже на хорошее решение для меня и моего друга. Но интервьюер думал иначе. Он попросил более простое решение. Пожалуйста, помогите мне, сообщив, как вы это сделаете в Java/C/C++?

Спасибо заранее.

  • 4
    Вам не нужно проверять, является ли сцепление (s2a, s2b) == s1, потому что вы знаете, что s2a равно началу s1. Вы можете просто проверить, если s2b == подстрока s1 от точки вращения до конца.
  • 33
    Как этот вопрос и лучший ответ получили так много голосов !?
Показать ещё 5 комментариев
Теги:

26 ответов

689
Лучший ответ

Сначала убедитесь, что s1 и s2 имеют одинаковую длину. Затем проверьте, является ли s2 подстрокой s1, объединенной с s1:

algorithm checkRotation(string s1, string s2) 
  if( len(s1) != len(s2))
    return false
  if( substring(s2,concat(s1,s1))
    return true
  return false
end

В Java:

boolean isRotation(String s1,String s2) {
    return (s1.length() == s2.length()) && ((s1+s1).indexOf(s2) != -1);
}
  • 1
    Очень хорошо. Что мне больше всего нравится, так это то, что ваш ответ на самом деле является хорошим способом определить «вращение». В качестве идентификатора вы также можете написать «return len (s1) == len (s2) && substring (s2, concat (s1, s1));», но это не обязательно лучший стиль, особенно для такой короткой функции.
  • 49
    Мне нравится его элегантность, но мне пришлось немного подумать, чтобы проверить, не было ли ложных срабатываний. (Я не думаю, что есть.)
Показать ещё 16 комментариев
101

Разумеется, лучшим ответом будет "Ну, я бы спросил сообщество stackoverflow и, вероятно, имел бы по крайней мере 4 действительно хорошие ответы в течение 5 минут". Мозги хорошие и все, но я бы поставил более высокую ценность на тех, кто знает, как работать с другими, чтобы получить решение.

  • 14
    +1 за чистую щеку. Сделал мой день :-)
  • 5
    Если они не согласны, вы можете связать их с этим вопросом.
Показать ещё 4 комментария
51

Другой пример python (на основе ответа):

def isrotation(s1,s2):
     return len(s1)==len(s2) and s1 in 2*s2
  • 1
    Интересно, что я подумал о дублировании s2 а не s1 тоже ... потом понял, что отношение в любом случае симметрично.
  • 1
    Если строка может быть длинной, вот версия Python, которая использует Boyer-Moore для получения O (n) времени выполнения: def isrotation (s1, s2): return len (s1) == len (s2) и re.compile (re .escape (s1)). search (2 * s2) не является None
Показать ещё 4 комментария
31

В то время как другие представили квадратичное решение для временной сложности времени, я бы добавил линейный (на основе KMP Algorithm):

bool is_rotation(const string& str1, const string& str2)
{
  if(str1.size()!=str2.size())
    return false;

  vector<size_t> prefixes(str1.size(), 0);
  for(size_t i=1, j=0; i<str1.size(); i++) {
    while(j>0 && str1[i]!=str1[j])
      j=prefixes[j-1];
    if(str1[i]==str1[j]) j++;
    prefixes[i]=j;
  }

  size_t i=0, j=0;
  for(; i<str2.size(); i++) {
    while(j>0 && str2[i]!=str1[j])
      j=prefixes[j-1];
    if(str2[i]==str1[j]) j++;
  }
  for(i=0; i<str2.size(); i++) {
    if(j>=str1.size()) return true;
    while(j>0 && str2[i]!=str1[j])
      j=prefixes[j-1];
    if(str2[i]==str1[j]) j++;
  }

  return false;
}

рабочий пример

  • 5
    +1 для ideone.com - выглядит очень интересно!
26

EDIT: принятый ответ явно более изящный и эффективный, чем этот, если вы его заметили. Я оставил этот ответ как то, что я сделал бы, если бы не думал о удвоении исходной строки.


Я бы просто переборщил. Сначала проверьте длину, а затем попробуйте каждое возможное смещение вращения. Если ни один из них не работает, верните false - если это произойдет, немедленно верните true.

Нет особой необходимости в конкатенации - просто используйте указатели (C) или индексы (Java) и пройдите по одной, по одной в каждой строке - начиная с начала одной строки и текущего смещения вращения кандидата во второй строке и если необходимо. Проверьте соответствие символов в каждой точке строки. Если вы дойдете до конца первой строки, вы закончили.

Скорее всего, это будет так же легко конкатенировать - хотя, вероятно, менее эффективно, по крайней мере, на Java.

  • 8
    +1 - нам не нужны никакие элегантные решения, которые в 3 раза более эффективны. Это C ... микрооптимизация является обязательной .
  • 1
    Поскольку это происходит раньше в stackoverflow, поиск от конца строки к началу обеспечивает механизм перехода, который может значительно увеличить скорость поиска подстроки. Из-за этого я бы сказал, что запускать его на месте не намного быстрее, особенно с помощью поиска с использованием грубой силы.
Показать ещё 11 комментариев
17

Здесь используется регулярное выражение только для удовольствия:

boolean isRotation(String s1, String s2) {
   return (s1.length() == s2.length()) && (s1 + s2).matches("(.*)(.*)\\2\\1");
}

Вы можете сделать это немного проще, если вы можете использовать специальный символ разделителя, который не должен быть в обеих строках.

boolean isRotation(String s1, String s2) {
   // neither string can contain "="
   return (s1 + "=" + s2).matches("(.*)(.*)=\\2\\1");
}

Вместо этого вы можете использовать lookbehind с конечным повторением:

boolean isRotation(String s1, String s2) {
   return (s1 + s2).matches(
      String.format("(.*)(.*)(?<=^.{%d})\\2\\1", s1.length())
   );
}
  • 6
    +1 для того, чтобы быть мастером регулярных выражений.
  • 0
    -1 За то, что слова «regex» и «fun» помещены в одно и то же утверждение, без изменения слова «fun» на «not» (только шучу, я не проголосовал)
Показать ещё 2 комментария
10

Whoa, whoa... почему все так взволнованы ответом O(n^2)? Я уверен, что здесь мы можем сделать лучше. Ответ выше включает операцию O(n) в цикле O(n) (вызов substring/indexOf). Даже с более эффективным алгоритмом поиска; скажем Boyer-Moore или KMP, худший вариант по-прежнему O(n^2) с дубликатами.

A O(n) рандомизированный ответ прост; возьмите хэш (например, отпечаток Rabin), который поддерживает скользящее окно O(1); хеш-строку 1, затем строку хеша 2, и перейдите к перемещению окна для хэш-1 вокруг строки и посмотрите, сталкиваются ли хеш-функции.

Если представить, что худший случай - это что-то вроде "сканирования двух нитей ДНК", то вероятность столкновения возрастает, и это, вероятно, вырождается до чего-то вроде O(n^(1+e)) или что-то (просто угадывая здесь).

Наконец, существует детерминированное решение O(nlogn), которое имеет очень большую постоянную вне. В принципе, идея состоит в том, чтобы взять свертку двух строк. Максимальное значение свертки будет разностью вращения (если они повернуты); проверяется проверка O(n). Приятно, что если есть два равных максимальных значения, то они оба являются также действительными решениями. Вы можете выполнить свертку с двумя БПФ и точечным продуктом и iFFT, поэтому nlogn + nlogn + n + nlogn + n == O(nlogn).

Поскольку вы не можете набивать нулями, и вы не можете гарантировать, что строки имеют длину 2 ^ n, БПФ не будут быстрыми; они будут медленными, все еще O(nlogn), но гораздо большей константой, чем алгоритм CT.

Все, что сказал, я абсолютно, на 100% уверен, что здесь есть детерминированное решение O(n), но штопает, если я могу его найти.

  • 0
    KMP для строки со сцепленным с самим собой (физически или виртуально с размером %stringsize ) гарантированно будет иметь линейное время.
  • 0
    +1 за Рабина-Карпа. В отличие от KMP, он использует постоянное пространство и его проще реализовать. (Это также первый ответ, о котором я подумал за несколько секунд, из-за которого трудно увидеть «правильный» ответ, потому что он тут же, и он приятен.) Ваша идея свертки напоминает мне алгоритм Шора - интересно, есть ли сублинейный квантовое решение - но это глупо сейчас, верно?
Показать ещё 1 комментарий
8

Вот O(n) и на месте alghoritm. Он использует оператор < для элементов строк. Это не мое, конечно. Я взял его из здесь (сайт на польском языке. Я наткнулся на него один раз в прошлом, и я не мог найти что-то в этом роде сейчас на английском, поэтому я показываю, что у меня есть:)).

bool equiv_cyc(const string &u, const string &v)
{
    int n = u.length(), i = -1, j = -1, k;
    if (n != v.length()) return false;

    while( i<n-1 && j<n-1 )
    {
        k = 1;
        while(k<=n && u[(i+k)%n]==v[(j+k)%n]) k++;
        if (k>n) return true;
        if (u[(i+k)%n] > v[(j+k)%n]) i += k; else j += k;
    }
    return false;
}
  • 0
    +1, интересная ссылка.
  • 0
    +1 , ... О (п) просто оооочень гораздо глубже с точки комп-Sci зрения , чем любой не O решения (п) :)
Показать ещё 2 комментария
8

Кулак, убедитесь, что 2 строки имеют одинаковую длину. Затем в C вы можете сделать это с помощью простой итерации указателя.


int is_rotation(char* s1, char* s2)
{
  char *tmp1;
  char *tmp2;
  char *ref2;

  assert(s1 && s2);
  if ((s1 == s2) || (strcmp(s1, s2) == 0))
    return (1);
  if (strlen(s1) != strlen(s2))
    return (0);

  while (*s2)
    {
      tmp1 = s1;
      if ((ref2 = strchr(s2, *s1)) == NULL)
        return (0);
      tmp2 = ref2;
      while (*tmp1 && (*tmp1 == *tmp2))
        {
          ++tmp1;
          ++tmp2;
          if (*tmp2 == '\0')
            tmp2 = s2;
        }
      if (*tmp1 == '\0')
        return (1);
      else
        ++s2;
    }
  return (0);
}
  • 19
    Ах, C. Зачем делать что-то наполовину и кодировать, когда это можно сделать на C!
  • 11
    +1 Это очень хорошо написано C. И, честно говоря, вопрос помечен буквой «c».
Показать ещё 4 комментария
7

Я думаю, что лучше сделать это в Java:

boolean isRotation(String s1,String s2) {
    return (s1.length() == s2.length()) && (s1+s1).contains(s2);
}

В Perl я бы сделал:

sub isRotation {
 my($string1,$string2) = @_;
 return length($string1) == length($string2) && ($string1.$string1)=~/$string2/;
}

или даже лучше использовать функцию index вместо регулярного выражения:

sub isRotation {
 my($string1,$string2) = @_;
 return length($string1) == length($string2) && index($string2,$string1.$string1) != -1;
}
  • 1
    Вы забыли \Q in /\Q$string2/ .
  • 0
    Зачем мне это использовать?
Показать ещё 1 комментарий
6

Возьмите каждый символ как амплитуду и выполните на них дискретное преобразование Фурье. Если они отличаются только вращением, частотные спектры будут одинаковыми с погрешностью округления. Конечно, это неэффективно, если длина не равна 2, поэтому вы можете делать БПФ: -)

  • 0
    Мы использовали это как интересное упражнение по кодированию, я не уверен, что мы сможем это оценить;).
  • 0
    БПФ ругал :) +1 от меня
6

Не уверен, что это наиболее эффективный метод, но он может быть относительно интересным: преобразование Burrows-Wheeler. Согласно статье WP, все повороты ввода дают одинаковый выход. Для таких приложений, как сжатие, это нежелательно, поэтому указывается исходное вращение (например, индексом, см. Статью). Но для простого независимого от вращения сравнения это звучит идеально. Конечно, это не обязательно идеально эффективно!

  • 0
    Поскольку преобразование Барроуза-Уилера включает в себя вычисление всех вращений струны, оно, безусловно, не будет оптимальным .. :-)
  • 0
    +1 за интересную ссылку.
5

Никто еще не предложил модульный подход, так вот один из них:

static void Main(string[] args)
{
    Console.WriteLine("Rotation : {0}",
        IsRotation("stackoverflow", "ztackoverflow"));
    Console.WriteLine("Rotation : {0}",
        IsRotation("stackoverflow", "ackoverflowst"));
    Console.WriteLine("Rotation : {0}",
        IsRotation("stackoverflow", "overflowstack"));
    Console.WriteLine("Rotation : {0}",
        IsRotation("stackoverflow", "stackoverflwo"));
    Console.WriteLine("Rotation : {0}",
        IsRotation("stackoverflow", "tackoverflwos"));
    Console.ReadLine();
}

public static bool IsRotation(string a, string b)
{
    Console.WriteLine("\nA: {0} B: {1}", a, b);

    if (b.Length != a.Length)
        return false;

    int ndx = a.IndexOf(b[0]);
    bool isRotation = true;
    Console.WriteLine("Ndx: {0}", ndx);
    if (ndx == -1) return false;
    for (int i = 0; i < b.Length; ++i)
    {
        int rotatedNdx = (i + ndx) % b.Length;
        char rotatedA = a[rotatedNdx];

        Console.WriteLine( "B: {0} A[{1}]: {2}", b[i], rotatedNdx, rotatedA );

        if (b[i] != rotatedA)
        {
            isRotation = false;
            // break; uncomment this when you remove the Console.WriteLine
        }
    }
    return isRotation;
}

Вывод:

A: stackoverflow B: ztackoverflow
Ndx: -1
Rotation : False

A: stackoverflow B: ackoverflowst
Ndx: 2
B: a A[2]: a
B: c A[3]: c
B: k A[4]: k
B: o A[5]: o
B: v A[6]: v
B: e A[7]: e
B: r A[8]: r
B: f A[9]: f
B: l A[10]: l
B: o A[11]: o
B: w A[12]: w
B: s A[0]: s
B: t A[1]: t
Rotation : True

A: stackoverflow B: overflowstack
Ndx: 5
B: o A[5]: o
B: v A[6]: v
B: e A[7]: e
B: r A[8]: r
B: f A[9]: f
B: l A[10]: l
B: o A[11]: o
B: w A[12]: w
B: s A[0]: s
B: t A[1]: t
B: a A[2]: a
B: c A[3]: c
B: k A[4]: k
Rotation : True

A: stackoverflow B: stackoverflwo
Ndx: 0
B: s A[0]: s
B: t A[1]: t
B: a A[2]: a
B: c A[3]: c
B: k A[4]: k
B: o A[5]: o
B: v A[6]: v
B: e A[7]: e
B: r A[8]: r
B: f A[9]: f
B: l A[10]: l
B: w A[11]: o
B: o A[12]: w
Rotation : False

A: stackoverflow B: tackoverflwos
Ndx: 1
B: t A[1]: t
B: a A[2]: a
B: c A[3]: c
B: k A[4]: k
B: o A[5]: o
B: v A[6]: v
B: e A[7]: e
B: r A[8]: r
B: f A[9]: f
B: l A[10]: l
B: w A[11]: o
B: o A[12]: w
B: s A[0]: s
Rotation : False

[EDIT: 2010-04-12]

piotr заметил недостаток в моем коде выше. Это ошибки, когда первый символ в строке происходит дважды или более. Например, stackoverflow, протестированный против owstackoverflow, привел к false, когда это должно быть правдой.

Спасибо piotr за обнаружение ошибки.

Теперь, здесь скорректированный код:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace TestRotate
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Rotation : {0}",
                IsRotation("stackoverflow", "ztackoverflow"));
            Console.WriteLine("Rotation : {0}",
                IsRotation("stackoverflow", "ackoverflowst"));
            Console.WriteLine("Rotation : {0}",
                IsRotation("stackoverflow", "overflowstack"));
            Console.WriteLine("Rotation : {0}",
                IsRotation("stackoverflow", "stackoverflwo"));
            Console.WriteLine("Rotation : {0}",
                IsRotation("stackoverflow", "tackoverflwos"));

            Console.WriteLine("Rotation : {0}",
                IsRotation("stackoverflow", "owstackoverfl"));

            Console.ReadLine();
        }

        public static bool IsRotation(string a, string b)
        {
            Console.WriteLine("\nA: {0} B: {1}", a, b);

            if (b.Length != a.Length)
                return false;

            if (a.IndexOf(b[0]) == -1 )
                return false;

            foreach (int ndx in IndexList(a, b[0]))
            {
                bool isRotation = true;

                Console.WriteLine("Ndx: {0}", ndx);

                for (int i = 0; i < b.Length; ++i)
                {
                    int rotatedNdx = (i + ndx) % b.Length;
                    char rotatedA = a[rotatedNdx];

                    Console.WriteLine("B: {0} A[{1}]: {2}", b[i], rotatedNdx, rotatedA);

                    if (b[i] != rotatedA)
                    {
                        isRotation = false;
                        break;
                    }
                }
                if (isRotation)
                    return true;
            }
            return false;
        }

        public static IEnumerable<int> IndexList(string src, char c)
        {
            for (int i = 0; i < src.Length; ++i)
                if (src[i] == c)
                    yield return i;
        }

    }//class Program
}//namespace TestRotate

Здесь вывод:

A: stackoverflow B: ztackoverflow
Rotation : False

A: stackoverflow B: ackoverflowst
Ndx: 2
B: a A[2]: a
B: c A[3]: c
B: k A[4]: k
B: o A[5]: o
B: v A[6]: v
B: e A[7]: e
B: r A[8]: r
B: f A[9]: f
B: l A[10]: l
B: o A[11]: o
B: w A[12]: w
B: s A[0]: s
B: t A[1]: t
Rotation : True

A: stackoverflow B: overflowstack
Ndx: 5
B: o A[5]: o
B: v A[6]: v
B: e A[7]: e
B: r A[8]: r
B: f A[9]: f
B: l A[10]: l
B: o A[11]: o
B: w A[12]: w
B: s A[0]: s
B: t A[1]: t
B: a A[2]: a
B: c A[3]: c
B: k A[4]: k
Rotation : True

A: stackoverflow B: stackoverflwo
Ndx: 0
B: s A[0]: s
B: t A[1]: t
B: a A[2]: a
B: c A[3]: c
B: k A[4]: k
B: o A[5]: o
B: v A[6]: v
B: e A[7]: e
B: r A[8]: r
B: f A[9]: f
B: l A[10]: l
B: w A[11]: o
Rotation : False

A: stackoverflow B: tackoverflwos
Ndx: 1
B: t A[1]: t
B: a A[2]: a
B: c A[3]: c
B: k A[4]: k
B: o A[5]: o
B: v A[6]: v
B: e A[7]: e
B: r A[8]: r
B: f A[9]: f
B: l A[10]: l
B: w A[11]: o
Rotation : False

A: stackoverflow B: owstackoverfl
Ndx: 5
B: o A[5]: o
B: w A[6]: v
Ndx: 11
B: o A[11]: o
B: w A[12]: w
B: s A[0]: s
B: t A[1]: t
B: a A[2]: a
B: c A[3]: c
B: k A[4]: k
B: o A[5]: o
B: v A[6]: v
B: e A[7]: e
B: r A[8]: r
B: f A[9]: f
B: l A[10]: l
Rotation : True

Здесь лямбда-подход:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IsRotation
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Rotation : {0}",
                IsRotation("stackoverflow", "ztackoverflow"));

            Console.WriteLine("Rotation : {0}",
                IsRotation("stackoverflow", "ackoverflowst"));

            Console.WriteLine("Rotation : {0}",
                IsRotation("stackoverflow", "overflowstack"));
            Console.WriteLine("Rotation : {0}",
                IsRotation("stackoverflow", "stackoverflwo"));

            Console.WriteLine("Rotation : {0}",
                IsRotation("stackoverflow", "owstackoverfl"));

            string strToTestFrom = "stackoverflow";
            foreach(string s in StringRotations(strToTestFrom))
            {
                Console.WriteLine("is {0} rotation of {1} ? {2}",
                    s, strToTestFrom,
                    IsRotation(strToTestFrom, s) );
            }
            Console.ReadLine();
        }

        public static IEnumerable<string> StringRotations(string src)
        {
            for (int i = 0; i < src.Length; ++i)
            {
                var sb = new StringBuilder();
                for (int x = 0; x < src.Length; ++x)
                    sb.Append(src[(i + x) % src.Length]);

                yield return sb.ToString();
            }
        }

        public static bool IsRotation(string a, string b)
        {
            if (b.Length != a.Length || a.IndexOf(b[0]) < 0 ) return false;
            foreach(int ndx in IndexList(a, b[0]))
            {
                int i = ndx;
                if (b.ToCharArray().All(x => x == a[i++ % a.Length]))
                    return true;
            }
            return false;
        }

        public static IEnumerable<int> IndexList(string src, char c)
        {
            for (int i = 0; i < src.Length; ++i)
                if (src[i] == c)
                    yield return i;
        }

    }//class Program

}//namespace IsRotation

Здесь вывод лямбда-выхода:

Rotation : False
Rotation : True
Rotation : True
Rotation : False
Rotation : True
is stackoverflow rotation of stackoverflow ? True
is tackoverflows rotation of stackoverflow ? True
is ackoverflowst rotation of stackoverflow ? True
is ckoverflowsta rotation of stackoverflow ? True
is koverflowstac rotation of stackoverflow ? True
is overflowstack rotation of stackoverflow ? True
is verflowstacko rotation of stackoverflow ? True
is erflowstackov rotation of stackoverflow ? True
is rflowstackove rotation of stackoverflow ? True
is flowstackover rotation of stackoverflow ? True
is lowstackoverf rotation of stackoverflow ? True
is owstackoverfl rotation of stackoverflow ? True
is wstackoverflo rotation of stackoverflow ? True
  • 0
    Я не думаю, что ваш ответ правильный, так как int ndx = a.IndexOf (b [0]); будет работать, только если в строке нет других элементов с таким же значением b [0].
  • 0
    спасибо за замечание недостатка. исправил это сейчас
3

Поскольку никто не дал решение на С++. вот он это:

bool isRotation(string s1,string s2) {

  string temp = s1;
  temp += s1;
  return (s1.length() == s2.length()) && (temp.find(s2) != string::npos);
}
  • 0
    Пара моментов: вы делаете относительно дорогую конкатенацию строк, даже если длины не совпадают; Вы можете передать s2 по константной ссылке.
2

И теперь для чего-то совершенно другого.

Если вам нужен очень быстрый ответ в ограниченном контексте, когда строки не вращаются друг от друга

  • вычислить некоторую символьную контрольную сумму (такую ​​как xoring все символы) на обеих строках. Если подписи различаются, то строки не являются вращениями друг друга.

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

2

Чистый ответ Java (sans null check)

private boolean isRotation(String s1,String s2){
    if(s1.length() != s2.length()) return false;
    for(int i=0; i < s1.length()-1; i++){
        s1 = new StringBuilder(s1.substring(1)).append(s1.charAt(0)).toString();
        //--or-- s1 = s1.substring(1) + s1.charAt(0)
        if(s1.equals(s2)) return true;
    }
    return false;
}
2

Мне нравится ответ, который проверяет, является ли s2 подстрокой s1, объединенной с s1.

Я хотел добавить оптимизацию, которая не теряет своей элегантности.

Вместо конкатенации строк вы можете использовать представление соединения (я не знаю другого языка, но для С++ Boost.Range предоставляют такие виды просмотров).

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

2

С#:

s1 == null && s2 == null || s1.Length == s2.Length && (s1 + s1).Contains(s2)
2

Операция простого простого поворота указателя работает, но она крайне неэффективна в худшем случае во время работы. Просто представьте себе строку со многими длинными повторяющимися прогонами символов, например:

S1 = HELLOHELLOHELLO1HELLOHELLOHELLO2

S2 = HELLOHELLOHELLO2HELLOHELLOHELLO1

Цикл "до тех пор, пока не произойдет рассогласование, а затем увеличится на единицу и повторите попытку" - это ужасный подход, вычисляемый.

Чтобы доказать, что вы можете сделать подход конкатенации в простой C без особых усилий, вот мое решение:

  int isRotation(const char* s1, const char* s2) {
        assert(s1 && s2);

        size_t s1Len = strlen(s1);

        if (s1Len != strlen(s2)) return 0;

        char s1SelfConcat[ 2 * s1Len + 1 ];

        sprintf(s1SelfConcat, "%s%s", s1, s1);   

        return (strstr(s1SelfConcat, s2) ? 1 : 0);
}

Это линейное время работы, за счет использования памяти O (n) в служебных целях.

(Обратите внимание, что реализация strstr() является специфичной для платформы, но, если ее особенно убить мозг, всегда можно заменить более быстрой альтернативой, такой как алгоритм Бойера-Мура)

  • 1
    Знаете ли вы о какой-либо платформе, которая имеет strstr() в O (n + m)? Кроме того, если стандарт (или что-то еще) не гарантирует вам линейное время выполнения strstr() , вы не можете утверждать, что весь алгоритм имеет линейную временную конкуренцию.
  • 0
    Вот почему я сказал, что его можно заменить алгоритмом Бойера-Мура, заставляя его работать за линейное время.
Показать ещё 1 комментарий
1

Отверните одну из строк. Возьмите БПФ обоих (рассматривая их как простые последовательности целых чисел). Умножьте результаты по точкам. Преобразуйте обратно с помощью обратного БПФ. Результат будет иметь один пик, если строки являются вращениями друг друга - положение пика будет указывать, насколько они вращаются относительно друг друга.

1

Очень легко писать на PHP с помощью функций strlen и strpos:

function isRotation($string1, $string2) {
    return strlen($string1) == strlen($string2) && (($string1.$string1).strpos($string2) != -1);
}

Я не знаю, что strpos использует внутренне, но если он использует KMP, это будет линейным по времени.

1

Другое решение Ruby на основе :

def rotation?(a, b); a.size == b.size and (b*2)[a]; end
0

Присоедините string1 к string2 и используйте алгоритм KMP, чтобы проверить, присутствует ли string2 во вновь сформированной строке. Поскольку временная сложность KMP меньше, чем substr.

0

Я бы сделал это в Perl:

sub isRotation { 
     return length $_[0] == length $_[1] and index($_[1],$_[0],$_[0]) != -1; 
}
0

Почему не что-то вроде этого?


//is q a rotation of p?
bool isRotation(string p, string q) {
    string table = q + q;    
    return table.IndexOf(p) != -1;
}

Конечно, вы могли бы написать свою собственную функцию IndexOf(); Я не уверен, что .NET использует наивный способ или более быстрый способ.

Наивный:


int IndexOf(string s) {
    for (int i = 0; i < this.Length - s.Length; i++)
        if (this.Substring(i, s.Length) == s) return i;
    return -1;
}

Быстрее


int IndexOf(string s) {
    int count = 0;
    for (int i = 0; i < this.Length; i++) {
        if (this[i] == s[count])
            count++;
        else
            count = 0;
        if (count == s.Length)
            return i - s.Length;
    }
    return -1;
}

Изменить: у меня могут быть проблемы с отдельными задачами; не хочется проверять.;)

0
int rotation(char *s1,char *s2)
{
    int i,j,k,p=0,n;
    n=strlen(s1);
    k=strlen(s2);
    if (n!=k)
        return 0;
    for (i=0;i<n;i++)
    {
        if (s1[0]==s2[i])
        {
            for (j=i,k=0;k<n;k++,j++)
            {
                if (s1[k]==s2[j])
                    p++;
                if (j==n-1)
                    j=0;
            }
        }
    }
    if (n==p+1)
      return 1;
    else
      return 0;
}
Сообщество Overcoder
Наверх
Меню