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

I need to find the longest sequence in a string with the caveat that the sequence must be repeated three or more times. So, for example, if my string is:

fdwaw4helloworldvcdv1c3xcv3xcz1sda21f2sd1ahelloworldgafgfa4564534321fadghelloworld

then I would like the value “helloworld” to be returned.

I know of a few ways of accomplishing this but the problem I’m facing is that the actual string is absurdly large so I’m really looking for a method that can do it in a timely fashion.

djechlin's user avatar

djechlin

58.8k34 gold badges161 silver badges288 bronze badges

asked Jun 18, 2012 at 20:09

Snesticle's user avatar

1

This problem is a variant of the longest repeated substring problem and there is an O(n)-time algorithm for solving it that uses suffix trees. The idea (as suggested by Wikipedia) is to construct a suffix tree (time O(n)), annotate all the nodes in the tree with the number of descendants (time O(n) using a DFS), and then to find the deepest node in the tree with at least three descendants (time O(n) using a DFS). This overall algorithm takes time O(n).

That said, suffix trees are notoriously hard to construct, so you would probably want to find a Python library that implements suffix trees for you before attempting this implementation. A quick Google search turns up this library, though I’m not sure whether this is a good implementation.

Another option would be to use suffix arrays in conjunction with LCP arrays. You can iterate over pairs of adjacent elements in the LCP array, taking the minimum of each pair, and store the largest number you find this way. That will correspond to the length of the longest string that repeats at least three times, and from there you can then read off the string itself.

There are several simple algorithms for building suffix arrays (the Manber-Myers algorithm runs in time O(n log n) and isn’t too hard to code up), and Kasai’s algorithm builds LCP arrays in time O(n) and is fairly straightforward to code up.

Hope this helps!

answered Jun 18, 2012 at 20:17

templatetypedef's user avatar

templatetypedeftemplatetypedef

360k101 gold badges890 silver badges1059 bronze badges

5

Use defaultdict to tally each substring beginning with each position in the input string. The OP wasn’t clear whether overlapping matches should or shouldn’t be included, this brute force method includes them.

from collections import defaultdict

def getsubs(loc, s):
    substr = s[loc:]
    i = -1
    while(substr):
        yield substr
        substr = s[loc:i]
        i -= 1

def longestRepetitiveSubstring(r, minocc=3):
    occ = defaultdict(int)
    # tally all occurrences of all substrings
    for i in range(len(r)):
        for sub in getsubs(i,r):
            occ[sub] += 1

    # filter out all substrings with fewer than minocc occurrences
    occ_minocc = [k for k,v in occ.items() if v >= minocc]

    if occ_minocc:
        maxkey =  max(occ_minocc, key=len)
        return maxkey, occ[maxkey]
    else:
        raise ValueError("no repetitions of any substring of '%s' with %d or more occurrences" % (r,minocc))

prints:

('helloworld', 3)

answered Jun 18, 2012 at 21:36

PaulMcG's user avatar

PaulMcGPaulMcG

62k16 gold badges93 silver badges130 bronze badges

1

Let’s start from the end, count the frequency and stop as soon as the most frequent element appears 3 or more times.

from collections import Counter
a='fdwaw4helloworldvcdv1c3xcv3xcz1sda21f2sd1ahelloworldgafgfa4564534321fadghelloworld'
times=3
for n in range(1,len(a)/times+1)[::-1]:
    substrings=[a[i:i+n] for i in range(len(a)-n+1)]
    freqs=Counter(substrings)
    if freqs.most_common(1)[0][1]>=3:
        seq=freqs.most_common(1)[0][0]
        break
print "sequence '%s' of length %s occurs %s or more times"%(seq,n,times)

Result:

>>> sequence 'helloworld' of length 10 occurs 3 or more times

Edit: if you have the feeling that you’re dealing with random input and the common substring should be of small length, you better start (if you need the speed) with small substrings and stop when you can’t find any that appear at least 3 time:

from collections import Counter
a='fdwaw4helloworldvcdv1c3xcv3xcz1sda21f2sd1ahelloworldgafgfa4564534321fadghelloworld'
times=3
for n in range(1,len(a)/times+1):
    substrings=[a[i:i+n] for i in range(len(a)-n+1)]
    freqs=Counter(substrings)
    if freqs.most_common(1)[0][1]<3:
        n-=1
        break
    else:
        seq=freqs.most_common(1)[0][0]
print "sequence '%s' of length %s occurs %s or more times"%(seq,n,times) 

The same result as above.

answered Jun 18, 2012 at 21:31

Max Li's user avatar

Max LiMax Li

5,0013 gold badges22 silver badges35 bronze badges

3

The first idea that came to mind is searching with progressively larger regular expressions:

import re

text = 'fdwaw4helloworldvcdv1c3xcv3xcz1sda21f2sd1ahelloworldgafgfa4564534321fadghelloworld'
largest = ''
i = 1

while 1:
    m = re.search("(" + ("w" * i) + ").*\1.*\1", text)
    if not m:
        break
    largest = m.group(1)
    i += 1

print largest    # helloworld

The code ran successfully. The time complexity appears to be at least O(n^2).

answered Jun 18, 2012 at 21:11

Matt Coughlin's user avatar

Matt CoughlinMatt Coughlin

18.6k3 gold badges46 silver badges59 bronze badges

1

If you reverse the input string, then feed it to a regex like (.+)(?:.*1){2}
It should give you the longest string repeated 3 times. (Reverse capture group 1 for the answer)

Edit:
I have to say cancel this way. It’s dependent on the first match. Unless its tested against a curr length vs max length so far, in an itterative loop, regex won’t work for this.

answered Jun 18, 2012 at 22:00

In Python you can use the string count method.
We also use an additional generator which will generate all the unique substrings of a given length for our example string.

The code is straightforward:

test_string2 = 'fdwaw4helloworldvcdv1c3xcv3xcz1sda21f2sd1ahelloworldgafgfa4564534321fadghelloworld'

def generate_substrings_of_length(this_string, length):
    ''' Generates unique substrings of a given length for a given string'''
    for i in range(len(this_string)-2*length+1):
        yield this_string[i:i+length]

def longest_substring(this_string):
    '''Returns the string with at least two repetitions which has maximum length'''
    max_substring = ''
    for subs_length in range(2, len(this_string) // 2 + 1):
        for substring in generate_substrings_of_length(this_string, subs_length):
            count_occurences = this_string.count(substring)
            if count_occurences > 1 :
                if len(substring) > len(max_substring) :
                    max_substring = substring
    return max_substring

I must note here (and this is important) that the generate_substrings_of_length generator does not generate all the substrings of a certain length. It will generate only the required substring to be able to make comparisons. Otherwise we will have some artificial duplicates. For example in the case :

test_string = "banana"

GS = generate_substrings_of_length(test_string , 2)
for i in GS: print(i)

will result :

ba
an
na

and this is enough for what we need.

answered Feb 18 at 10:52

youth4ever's user avatar

youth4everyouth4ever

1984 silver badges13 bronze badges

from collections import Counter

def Longest(string):

    b = []
    le = []

    for i in set(string):

        for j in range(Counter(string)[i]+1): 
            b.append(i* (j+1))

    for i in b:
        if i in string:
            le.append(i)


    return ([s for s in le if len(s)==len(max( le , key = len))])

xskxzr's user avatar

xskxzr

12.3k12 gold badges37 silver badges76 bronze badges

answered Mar 12, 2019 at 16:07

FellerRock's user avatar

Необходимо найти максимальную по длине последовательность цифр в строке.

lists = []   # Создание пустого массива
inputString = input("Введите строку: ") #Ввод исходной строки
xArr = list(inputString) # Разбитие строки на массив из элементов строки
MaxInt = 0 # Максимальная длина чисел
index = 0 # индекс массива xArr
while index <= len(xArr): # Пока индекс меньше равен длине Массива
  if type(xArr[index]) == int: # если индекс равен числовому типу 
    MaxInt = MaxInt + 1 # инкремент Длины чисел
    index += 1 # инкремент индекса
  if type(xArr[index + 1]) == str or index == len(xArr): # если след символ 
   # строки символ или конец строки
    lists.append(MaxInt) # добавление в конец массива с макс значениями 
     #текущую макс длину цифр
    MaxInt = 0 # обнуляю макс значение
    break # останавливаю цикл

print(max(lists))  # Макс значение из массива с макс значениями

Blacit's user avatar

Blacit

1,3751 золотой знак16 серебряных знаков37 бронзовых знаков

задан 6 ноя 2019 в 12:43

E_R_H_A_N's user avatar

5

Это можно очень просто решить регулярными выражениями.

Регулярное выражение d+ ищет последовательности цифр, а re.findall вернет строки с результатом.

Останется список строк превратить в список длин строк и получить максимальное значение.

Пример:

import re

text = input("Введите строку: ")
items = re.findall('d+', text)
max_len = max(len(x) for x in items)
print(max_len)

Консоль:

Введите строку: 12 abcsd232 df12124 5555555
7

UPD.

Через цикл:

text = '12 abcsd232 df12124 5555555'
max_len = 0
cur_len = 0

for c in text:
    if c in '0123456789':
        cur_len += 1
    else:
        if cur_len > max_len:
            max_len = cur_len
        cur_len = 0

if cur_len > max_len:
    max_len = cur_len

print(max_len)  # 7

Или:

text = '12 abcsd232 df12124 5555555'
max_len = 0
cur_len = 0

for i in range(len(text)):
    c = text[i]
    if c in '0123456789':
        cur_len += 1
    elif cur_len > max_len:
        max_len = cur_len
        cur_len = 0

    # Конец строки
    if i == len(text) - 1 and cur_len > max_len:
        max_len = cur_len

print(max_len)  # 7

ответ дан 6 ноя 2019 в 12:57

gil9red's user avatar

gil9redgil9red

76.3k6 золотых знаков51 серебряный знак117 бронзовых знаков

4

input() всегда выдает строку, поэтому условие if type(xArr[index]) == int не выполнится никогда. Нужно его заменить, например, на такое:

if xArr[index] in "0123456789":

Второй if просто заменить на else и убрать оттуда break конечно же. То условие не делает ничего нужного.

ответ дан 6 ноя 2019 в 12:59

Эникейщик's user avatar

ЭникейщикЭникейщик

25.1k7 золотых знаков30 серебряных знаков46 бронзовых знаков

1

input возвращает str.
В цикле необходимо делать проверку с помощью метода str.isdigit().
Так же можно через ord(), зная какие коды возвращают цифры.

ответ дан 6 ноя 2019 в 14:17

sdmnt's user avatar

sdmntsdmnt

54 бронзовых знака

a= '12 abcsd232 df12124 5555555'
maxdig = max(len(b) for b in ''.join([a[i] if a[i].isdigit() else ' ' for i in range(len(a))]).split())
print(maxdig)

Идея простая.

  1. из строки делаем новую, заменяя не-цифры на пробелы

    ''.join([a[i] if a[i].isdigit() else ' ' for i in range(len(a))
    
  2. Делаем генератор выражения, разделяя по пробелу и а в качестве выражения длины. Ищем максимум.

aleksandr barakin's user avatar

ответ дан 16 ноя 2022 в 11:10

Джошуа Сургутский's user avatar



Ученик

(85),
на голосовании



2 года назад

Голосование за лучший ответ

port port

Искусственный Интеллект

(181477)


2 года назад

На тебе for…

s=’ssbbbsssbc’

count=0
result=0
for i in s:
~~if i==’s’: count+=1
~~else:
~~~~if count>result: result=count; count=0
if count>result: result=count;
print (result)

Сергей ВилковУченик (85)

2 года назад

Результат получается = 5, а это не правильно. Вы считаете общее количество “s”, а не самую длинную её последовательность.

Сергей ВилковУченик (85)

2 года назад

И всё-равно вы считаете общую сумму “s”, а в условие задачи нужно: подсчитывать самую длинную последовательность подряд идущих букв “s” и выводит ответ на экран?

Тимур Пономарёв

Мастер

(1432)


2 года назад

Что тут интересного? Если тебе нужно написать программу то просто иди в цикле for до конца строки и символы сравнивает
stroka = input()
counter = 1
max = 0
for i in range(1, len(stroka)):
____if stroka[i] == stroka[i-1] == ‘s’:
________counter = counter + 1
________if counter > max:
____________max = counter
____else:
________counter = 1
print(max)

Veter .

Мастер

(1105)


2 года назад

Сергей ВилковУченик (85)

2 года назад

Вот в этом то и дело (и вся сложность простой задачи), что нужно решить без этого!?

Сергей ВилковУченик (85)

2 года назад

Вот так можно переложить ваш код на простой “язык”!

print(‘Введите строку: ‘, end = ”)
text = input()
text += ”
count_s = 0
letter = 0

for symbol in text:
if symbol == ‘s’:
letter += 1
else:
if letter > count_s:
count_s = letter
letter = 0
print(‘Самая длинная последовательность: ‘, count_s)

SkkkN

Профи

(776)


1 год назад

string = input(‘Введите строку: ‘)
count = 0
result = 0

for symbol in string:
~~if symbol == ‘s’:
~~~~count += 1
~~elif count < result and symbol != ‘s’:
~~~~count = 0
~~else:
~~~~if count > result:
~~~~~~result = count
~~~~~~count = 0
if count > result:
~~result = count

print(‘Самая длинная последовательность: ‘, result)

Продолжаем разбирать задачи с сайта LeetCode. На этот раз — посложнее:

Есть строка s — нужно найти длину самой длинной подстроки, в которой каждый символ используется только один раз.

Например:

если s = “abcabcbb”, то ответ будет 3, потому что строка без повторений — это “abc”;

если s = “bbbbb”, то ответ будет 1, потому что самая длинная подстрока тут будет из одного символа;

если s = “pwwkew”, то ответ будет 3, потому что тут две самые одинаково длинные подстроки — “wke” и “kew”, в которых по 3 символа.

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

Решение: использовать встроенные функции для работы со строками

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

Например, если у нас в подстроке хранится “abcdf” и мы снова встречаем b, то делаем так:

  1. Получаем номер символа b в подстроке → он равен 1 (если интересно, почему не 2, — почитайте, почему счёт в программировании начинается с нуля, а не с единицы).
  2. Формируем новую строку, начиная с 1 символа и до конца → “cdf”.
  3. Добавляем к ней в конец наш текущий символ b → “cdfb”.

Так шаг за шагом мы проверим все вложенные строки и найдём самую длинную без повторов. Звучит сложно, но в коде всё выглядит гораздо проще. Почитайте комментарии, чтобы разобраться в каждом шаге:

# исходная строка
s = 'abcabcdcc'

# здесь будет наш ответ
res = 0
# на старте у нас пустая подстрока
sub = ''
# перебираем все символы в исходной строке
for char in s:
	# если символа нет в подстроке
	if char not in sub:
		# добавляем его туда
		sub += char
		# смотрим, максимальный ли это результат, и если да — запоминаем его
		res = max(res, len(sub))
	# если символ в подстроке есть
	else:
		# получаем индекс текущего символа в подстроке
		cut = sub.index(char)
		# сокращаем нашу подстроку: оставляем только то, что идёт после символа-дубликата, и добавляем к строке текущий символ
		sub = sub[cut+1:] + char
		
# выводим результат на экран
print(res)

Решение: проверить всю вложенную строку

Зайдём с другой стороны — напишем функцию, которая будет проверять, есть в указанной подстроке повторяющиеся символы или нет. Логика будет такая:

  1. Передаём в функцию начальный и конечный индекс, который определяет границы подстроки.
  2. Заводим массив, в который будем складывать проверенные символы и проверять на дубли.
  3. По очереди проверяем все символы в указанном диапазоне и смотрим, есть ли очередной символ в нашем массиве.
  4. Если есть — выводим False, что означает, что в подстроке есть повторяющиеся символы.
  5. Если символа нет — добавляем его в наш массив.
  6. Если мы проверили все символы и ни одного не было в том массиве — возвращаем True, то есть повторов нет.

Теперь запишем это на Python:

# исходная строка
s = 'abcabcdcc'

# функция, которая проверит, есть ли в подстроке повторяющиеся символы
# на вход отправляем начальную и конечную позицию в строке для проверки
def check(start, end):
    # создаём пустое множество
    chars = set()
    # делаем цикл от начального до конечного символа
    for i in range(start, end + 1):
        # получаем очередной символ из строки
        c = s[i]
        # если символа уже есть в множестве
        if c in chars:
			# возвращаем False — в строке есть повторяющиеся символы
            return False
		# добавляем символ в множество
        chars.add(c)
	# если дошли досюда — возвращаем True
    return True

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

# --- основной алгоритм ---
# получаем длину строки
n = len(s)
# здесь будет наш ответ
res = 0
# перебираем символы от первого до последнего
for i in range(n):
	# перебираем символы от текущего до последнего
    for j in range(i, n):
		# если в получившейся подстроке нет повторяющихся символов
        if check(i, j):
			# смотрим, максимальный ли это результат, и если да — запоминаем его
            res = max(res, j - i + 1)
# выводим результат на экран
print(res)

Объединим обе части и получим готовый код:

# исходная строка
s = 'abcabcdcc'

# функция, которая проверит, есть ли в подстроке повторяющиеся символы
# на вход отправляем начальную и конечную позицию в строке для проверки
def check(start, end):
    # создаём пустое множество
    chars = set()
    # делаем цикл от начального до конечного символа
    for i in range(start, end + 1):
        # получаем очередной символ из строки
        c = s[i]
        # если символа уже есть в множестве
        if c in chars:
			# возвращаем False — в строке есть повторяющиеся символы
            return False
		# добавляем символ в множество
        chars.add(c)
	# если дошли досюда — возвращаем True
    return True

# --- основной алгоритм ---
# получаем длину строки
n = len(s)
# здесь будет наш ответ
res = 0
# перебираем символы от первого до последнего
for i in range(n):
	# перебираем символы от текущего до последнего
    for j in range(i, n):
		# если в получившейся подстроке нет повторяющихся символов
        if check(i, j):
			# смотрим, максимальный ли это результат, и если да — запоминаем его
            res = max(res, j - i + 1)
# выводим результат на экран
print(res)

Вёрстка:

Кирилл Климентьев

29.12.2019Python, Программы Python

Если задана строка (может содержать как буквы, так и цифры), напишите программу на Python, чтобы найти самую длинную последовательность букв и цифр.

Примеры:

Input : geeks123available
Output : ('available', 123)

Input : 98apple658pine
Output : ('apple', 658)

Подход № 1: грубая сила
Это наивный или грубый метод, позволяющий найти самую длинную последовательность букв и цифр. Мы берем две строковые переменные типа longest_letter и longest_digit . Запускаем цикл и проверяем последовательные подстроки букв и цифр. На каждой итерации мы проверяем, больше ли текущая буквенная подстрока, чем самая длинная буквенная или цифровая подстрока соответственно. Если да, мы присваиваем текущую подстроку буквы и цифры самой длинной букве и подстроке цифры соответственно. В противном случае ничего не делать.

import re

def longestSubstring(s):

    longest_letterSeq = ''

    longest_digitSeq = ''

    i = 0

    while(i<len(s)):

        curr_letterSeq = ''

        curr_digitSeq = ''

        while(i<len(s) and s[i].isalpha()):

            curr_letterSeq += s[i]

            i+= 1

        while(i<len(s) and s[i].isdigit()):

            curr_digitSeq += s[i]

            i+= 1

        if(i< len(s) and not(s[i].isdigit()) 

                     and not(s[i].isalpha())) :

            i+= 1

        if(len(curr_letterSeq) > len(longest_letterSeq) ):

            longest_letterSeq = curr_letterSeq

        if(len(curr_digitSeq) > len(longest_digitSeq) ):

            longest_digitSeq = curr_digitSeq

    return longest_letterSeq, longest_digitSeq

str = '3Geeksfor123geeks3'

print(longestSubstring(str))

Выход:

('Geeksfor', '123')

Подход № 2: Использование регулярных выражений Python
Python Regex является еще одним методом решения данной проблемы. Найдите последовательность подстрок из цифр и букв, используя регулярное выражение Python, а затем найдите самую длинную длину подстроки соответственно.

import re

def longestSubstring(str):

    letter = max(re.findall(r'D+', str), key = len)

    digit = max(re.findall(r'd+', str), key = len)

    return letter, digit

str = 'geeks123geeksforgeeks1'

print(longestSubstring(str))

Выход:

('geeksforgeeks', '123')

Рекомендуемые посты:

  • SequenceMatcher в Python для самой длинной общей подстроки
  • Python | Найти элементы списка, начинающиеся с определенной буквы
  • Карта Питона | Длина самого длинного последовательного 1 в двоичном представлении данного целого числа
  • Регулярное выражение Python для поиска последовательностей из одной заглавной буквы, за которой следуют строчные буквы
  • Python | Найти последнее вхождение подстроки
  • Python | Способы поиска n-го вхождения подстроки в строке
  • Python | Найти k самых длинных слов в данном списке
  • Python | Способы проверить, содержит ли данная строка только букву
  • Python | Все вхождения подстроки в строку
  • Python | Получить строку после появления данной подстроки
  • Python | Частота подстроки в данной строке
  • Python | Добавить подстроку по определенному индексу
  • Python | Удалить указанную подстроку из конца строки
  • Python | Соответствие ключа подстроки в словаре
  • Python | Проверьте, присутствует ли подстрока в строке

Python | Найти самую длинную последовательность букв и цифр

0.00 (0%) 0 votes

Добавить комментарий