Подтвердить что ты не робот

Как найти повторяющуюся последовательность символов в заданном массиве?

Моя проблема - найти повторяющуюся последовательность символов в данном массиве. просто, чтобы определить шаблон, в котором появляются символы.

   .---.---.---.---.---.---.---.---.---.---.---.---.---.---.
1: | J | A | M | E | S | O | N | J | A | M | E | S | O | N |
   '---'---'---'---'---'---'---'---'---'---'---'---'---'---'

   .---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.
2: | R | O | N | R | O | N | R | O | N | R | O | N | R | O | N |
   '---'---'---'---'---'---'---'---'---'---'---'---'---'---'---'

   .---.---.---.---.---.---.---.---.---.---.---.---.
3: | S | H | A | M | I | L | S | H | A | M | I | L |
   '---'---'---'---'---'---'---'---'---'---'---'---'

   .---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.
4: | C | A | R | P | E | N | T | E | R | C | A | R | P | E | N | T | E | R |
   '---'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---'

Пример

Учитывая предыдущие данные, результат должен быть:

  • "JAMESON"
  • "RON"
  • "SHAMIL"
  • "CARPENTER"

Вопрос

  • Как эффективно решать эту проблему?
4b9b3361

Ответ 1

Для ваших примеров первым моим подходом было бы

  • получить первый символ массива (для вашего последнего примера это будет C)
  • получить индекс следующего появления этого символа в массиве (например, 9)
  • если он найден, найдите следующий вид подстроки между двумя появлениями символа (в этом случае CARPENTER)
  • если он найден, вы закончили (и результат - это подстрока).

Конечно, это работает только для очень ограниченного подмножества возможных массивов, где одно и то же слово повторяется снова и снова, начиная с самого начала, без случайных символов между ними, и его первый символ не повторяется внутри слова, Но все ваши примеры попадают в эту категорию - и я предпочитаю самое простое решение, которое могло бы работать: -)

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

Обратите внимание, что этот расширенный алгоритм даст другой результат для вашего второго примера, а именно RONRON вместо RON.

Ответ 2

Решение по языку O (NlogN)

Выполнение БПФ на вашей строке (обработка символов как числовых значений). Каждый пик в полученном графе соответствует периодичности подстроки.

Ответ 3

В Python вы можете использовать регулярные выражения таким образом:

def recurrence(text):
    import re
    for i in range(1, len(text)/2 + 1):
        m = re.match(r'^(.{%d})\1+$'%i, text)
        if m: return m.group(1)

recurrence('abcabc') # Returns 'abc'

Я не уверен, как это переводится на Java или C. (Это одна из причин, по которой мне нравится Python.: -)

Ответ 4

Сначала напишите метод, который находит повторяющуюся подстроку sub в строке контейнера, как показано ниже.

boolean findSubRepeating(String sub, String container);

Теперь продолжайте вызывать этот метод с увеличением подстроки в контейнере, сначала попробуйте 1 символьную подстроку, затем 2 символа и т.д. вверх до container.length/2.

Ответ 5

Псевдокод

len = str.length
for (i in 1..len) {
   if (len%i==0) {
      if (str==str.substr(0,i).repeat(len/i)) {
         return str.substr(0,i)
      }
   }
}

Примечание. Для краткости я изобретаю метод "повторения" для строк, который на самом деле не является частью строки Java; "ABC".repeat(2) = "abcabc"

Ответ 6

Использование С++:

//Splits the string into the fragments of given size
//Returns the set of of splitted strings avaialble
set<string> split(string s, int frag)
{
    set<string> uni;
    int len = s.length();
    for(int i = 0; i < len; i+= frag)
    {
        uni.insert(s.substr(i, frag));
    }

    return uni;
}

int main()
{

    string out;
    string s = "carpentercarpenter";
    int len = s.length();

      //Optimistic approach..hope there are only 2 repeated strings
      //If that fails, then try to break the strings with lesser number of
      //characters
    for(int i = len/2; i>1;--i)
    {
        set<string> uni = split(s,i);
        if(uni.size() == 1)
        {
            out = *uni.begin();
            break;
        }
    }

    cout<<out;
    return 0;

}

Ответ 7

Первая мысль, которая приходит мне на ум, - это попытка повторить последовательности длин, которые делят длину (S) = N. Существует максимум N/2 таких длин, поэтому это приводит к алгоритму O (N ^ 2).

Но я уверен, что его можно улучшить...

Ответ 8

и вот конкретный рабочий пример:

/* find greatest repeated substring */
char *fgrs(const char *s,size_t *l)
{
  char *r=0,*a=s;
  *l=0;
  while( *a )
  {
    char *e=strrchr(a+1,*a);
    if( !e )
      break;
    do {
      size_t t=1;
      for(;&a[t]!=e && a[t]==e[t];++t);
      if( t>*l )
        *l=t,r=a;
      while( --e!=a && *e!=*a );
    } while( e!=a && *e==*a );
    ++a;
  }
  return r;
}

  size_t t;
  const char *p;
  p=fgrs("BARBARABARBARABARBARA",&t);
  while( t-- ) putchar(*p++);
  p=fgrs("0123456789",&t);
  while( t-- ) putchar(*p++);
  p=fgrs("1111",&t);
  while( t-- ) putchar(*p++);
  p=fgrs("11111",&t);
  while( t-- ) putchar(*p++);

Ответ 9

Я бы преобразовал массив в объект String и использовал regex

Ответ 10

Не знаете, как вы определяете "эффективно". Для простой/быстрой реализации вы можете сделать это в Java:

    private static String findSequence(String text) {
        Pattern pattern = Pattern.compile("(.+?)\\1+");
        Matcher matcher = pattern.matcher(text);
        return matcher.matches() ? matcher.group(1) : null;
    }

он пытается найти кратчайшую строку (.+?), которая должна повторяться как минимум один раз (\1+), чтобы соответствовать всему входному тексту.

Ответ 11

Поместите весь свой символ в массив e.x. а []

i=0; j=0;
for( 0 < i < count ) 
{
if (a[i] == a[i+j+1])
    {++i;}
else
    {++j;i=0;}
}

Тогда отношение (i/j) = количество повторов в вашем массиве. Вы должны обратить внимание на пределы i и j, но это простое решение.

Ответ 12

Вот более общее решение проблемы, которое найдет повторяющиеся подпоследовательности в последовательности (чего-либо), где подпоследовательности не должны начинаться в начале и не сразу следовать друг за другом.

задана последовательность b [0..n], содержащая данные, о которых идет речь, а порог t - минимальная длина подпоследовательности, чтобы найти,

l_max = 0, i_max = 0, j_max = 0;
for (i=0; i<n-(t*2);i++) {
  for (j=i+t;j<n-t; j++) {
    l=0;
    while (i+l<j && j+l<n && b[i+l] == b[j+l])
      l++;
    if (l>t) {
      print "Sequence of length " + l + " found at " + i + " and " + j);
      if (l>l_max) {
        l_max = l;
        i_max = i;
        j_max = j;
      }
    }
  }
}
if (l_max>t) {
  print "longest common subsequence found at " + i_max + " and " + j_max + " (" + l_max + " long)";
}

В основном:

  • Начните с начала данных, итерации до тех пор, пока не достигните 2 * t конца (нет возможного способа иметь две различные подпоследовательности длины t менее чем за 2 * т пространства!)
  • Для второй подпоследовательности запустите, по крайней мере, t байт, где начинается первая последовательность.
  • Затем reset длина обнаруженной подпоследовательности до 0 и проверьте, есть ли у вас общий символ в я + l и j + l. Пока вы делаете, увеличивайте l. Когда у вас больше нет общего характера, вы достигли конца вашей общей подпоследовательности. Если подпоследовательность больше порога, напечатайте результат.