Как найти одинаковые подстроки

Copy-paste detector есть в PMD: pmd.sourceforge.net/pmd-5.0.1/cpd.html (не нашел сходу нормального описания на их сайте; когда-то видел статью про то, как он устроен: там суффиксный массив).

Если нужен именно алгоритм, то за O(N log N) (или, если постараться, O(N)) в худшем случае можно использовать суффиксный массив, суффиксное дерево или суффиксный автомат (осторожно, статьи ориентированы на спортивное программирование, стиль кода может быть непривычным).

Пожалуй, проще всего работать с суффиксным массивом: это просто все суффиксы строки, упорядоченные в лексикографическом порядке (конечно, сами суффиксы хранятся не как строки, а как индексы начала). Для всех пар соседних суффиксов можно быстро найти LCP (наибольший общий префикс). Пусть дана минимальная длина (назовем ее L) искомых подстрок. Если в суффиксном массиве нашлись K последовательных (в лексикографическом порядке) суффиксов таких, что LCP любых двух соседних не меньше L, то LCP их всех есть подстрока исходной строки, входящая в нее хотя бы K раз. Используя эту идею, за O(N log N) можно, например, найти все подстроки длины L, встречающиеся хотя бы K раз (хотя это проще сделать хешами, как предложил mihaildemidoff). Наверно, можно аналогично перебирать подходящие строки в порядке убывания длины или количества вхождений. Но наверно это удобнее делать суффиксным деревом.

Наверно, прямо при построении суффиксного дерева можно для каждой вершины найти количество вхождений соответствующей ей подстроки. Таким образом, мы найдем вообще для каждой подстроки количество ее вхождений. Но чтобы получилось O(N), а не O(N^2) данных, подстроки будут разбиты на группы (соответствующие вершинам дерева) с одинаковым количеством вхождений, и все произойдет за O(N). Того же самого можно (проще в реализации и сложнее в понимании) добиться и суффиксным автоматом (он в некотором смысле двойственен суффиксному дереву). Такой конструкции, наверно, достаточно для решения поставленной задачи в любой разумной конкретной формулировке.

Я не уверен что reduce совсем то, reduce это перебор массива с имеющимся первым параметром, у которого задается значение изначально, после каждого раза когда происходит return, значение меняется на получившееся, а второй параметр это значение из массива

var arr = [1, 2, 3, 4, 5]

var result = arr.reduce(function(sum, current) { // sum меняется каждый раз после прохода
  return sum + current;
}, 0); // 0 - изначальный параметр который задается

А вот вариант ответа, который я могу предложить, павда для больших значений он долгий

var arr = ['qwert4', 'qwert7y', 'qwers4', 'qw4qwer'], 
    ind = -1;

for(var i =0; i < arr.length - 2; i++) {

  while(true) {

    if( arr[i][ind] == arr[i+1][ind] && ind == -1 ) 
      ind++;
    else if( arr[i][ind] == arr[i+1][ind] ) 
      ind++;
    else 
      ind--;
      break;
  }
}

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

Поиск одинаковых подстрок.

Очень часто надо найти не что-то конкретное, а непонятно что, но такое-же, как что-то, что уже есть. Именно для этого используются обратные ссылки.
Я уже приводил маленький, но чрезвычайно важный пример поиска двух одинаковых строк, в котором RE совпадает тогда, и только тогда, когда строки одинаковые. Давайте рассмотрим ещё один пример:

В этом примере, sed выделяет строки цветом, в которых есть две одинаковые маленькие латинские буквы.
Основное в этом скрипте — это регулярное выражение

Его можно прочитать так: найти любую малую латинскую букву, после которой идёт точно такая-же буква, возможно не сразу.

Вы можете обсудить этот документ на форуме. Текст предоставляется по лицензии GNU Free Documentation License (Перевод лицензии GFDL).

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

Is there any efficient way to find the duplicate substring? Here, duplicate means that two same substring close to each other have the same value without overlap. For example, the source string is:

ABCDDEFGHFGH

‘D’ and ‘FGH’ is duplicated. ‘F’ appear two times in the sequence, however, they are not close to each other, so it does not duplicate. so our algorithm will return [‘D’, ‘FGH’]. I want to know whether there exists an elegant algorithm instead the brute force method?

asked Dec 22, 2016 at 11:25

maple's user avatar

maplemaple

1,8042 gold badges19 silver badges28 bronze badges

4

Not very efficient (suffix tree/array are better for very large strings), but very short regular expression solution (C#):

  string source = @"ABCDDEFGHFGH";

  string[] result = Regex
    .Matches(source, @"(.+)1")
    .OfType<Match>()
    .Select(match => match.Groups[1].Value)
    .ToArray(); 

Explanation

(.+) - group of any (at least 1) characters
1   - the same group (group #1) repeated 

Test

  Console.Write(string.Join(", ", result));     

Outcome

  D, FGH

In case of ambiguity, e.g. "AAAA" where we can provide "AA" as well as "A" the solution performs greedy and thus "AA" is returned.

answered Dec 22, 2016 at 12:21

Dmitry Bychenko's user avatar

Dmitry BychenkoDmitry Bychenko

178k19 gold badges159 silver badges213 bronze badges

Without using any regex which might turn out to be very slow, I guess it’s best to use two cursors running hand to hand. The algorithm is pretty obvious from the below JS code.

function getNborDupes(s){
  var cl = 0,  // cursor left
      cr = 0,  // cursor right
      ts = "", // test string
     res = []; // result array
  while (cl < s.length){
    cr = cl;
    while (++cr < s.length){
      ts = s.slice(cl,cr);  // ts starting from cl to cr (char @ cr excluded)
      
      // check ts with subst from cr to cr + ts.length (char @ cr + ts.length excluded)
      // if they match push it to result advance cursors to cl + ts.length and continue
      
      ts === s.substr(cr,ts.length) && (res.push(ts), cl = cr += ts.length);
    }
  cl++;
  }
  return res;
}

var str = "ABCDDEFGHFGH";
console.log(getNborDupes(str));

Throughout the whole process ts will take the following values.

A
AB
ABC
ABCD
ABCDD
ABCDDE
ABCDDEF
ABCDDEFG
ABCDDEFGH
ABCDDEFGHF
ABCDDEFGHFG
B
BC
BCD
BCDD
BCDDE
BCDDEF
BCDDEFG
BCDDEFGH
BCDDEFGHF
BCDDEFGHFG
C
CD
CDD
CDDE
CDDEF
CDDEFG
CDDEFGH
CDDEFGHF
CDDEFGHFG
D
E
EF
EFG
EFGH
EFGHF
EFGHFG
F
FG
FGH

Though the cl = cr += ts.length part decides whether or not to re-start searching on from before or after the matching sub-string. As of currently the above code; "ABABABAB" input would return ["AB","AB"] for but if you make it cr = cl += ts.length then you should expect the result to be ["AB", "AB", "AB"].

answered Dec 22, 2016 at 14:35

Redu's user avatar

ReduRedu

24.8k6 gold badges56 silver badges74 bronze badges

2

Python – мощный язык программирования, который подходит для решения множества задач. Одной из таких задач является поиск одинаковых подстрок в строках.

Что такое подстрока?

Подстрока – это часть строки, которая находится внутри нее. Например, если у нас есть строка «Hello, world!», то её подстрокой может быть «world» или «ell».

Как найти одинаковую подстроку в двух строках?

Для того, чтобы найти одинаковую подстроку в двух строках, можно использовать алгоритм наименьшей общей подстроки (Longest Common Substring). В Python для этого можно воспользоваться библиотекой difflib:

import difflib

string1 = "Hello, world!"
string2 = "Goodbye, world!"

matcher = difflib.SequenceMatcher(None, string1, string2)
match = matcher.find_longest_match(0, len(string1), 0, len(string2))
matched_string = string1[match.a: match.a + match.size]

print(matched_string)

Этот код выведет на экран строку «world», которую содержат обе исходные строки.

Как найти все одинаковые подстроки в строке?

Чтобы найти все одинаковые подстроки в строке, можно воспользоваться функцией findall из библиотеки re (Regular Expression):

import re

string = "Peter Piper picked a peck of pickled peppers. A peck of pickled peppers Peter Piper picked."

pattern = re.compile(r'b(w+)b(?=.*b1b)')
matches = pattern.findall(string)

print(matches)

Этот код выведет на экран список строк, которые содержатся в string и встречаются более одного раза.

Вывод

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

Понравилась статья? Поделить с друзьями:

Не пропустите также:

  • Как найти сюжет для повести
  • Как мишка найди мишку
  • Как найти этот номер в вацапе
  • Как исправить мертвый зуб
  • Белые семечки как исправить

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии