Помогите найти ошибку. (Python)

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

Условие

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

Формат ввода

Одна строка с текстом. Длина строки не превосходит 100 символов. В строку входят только символы с ASCII-кодом от 32 до 126 включительно.

Формат вывода

Нужно вывести N строк, где N — количество различных символов в строке. В каждой из этих строк сначала должен идти символ, для которого она пишется, затем, через пробел, длина максимальной подстроки, состоящей только из такого символа. Строки вывода должны быть отсортированы лексикографически.

Примеры:

Пример 1

введите сюда описание изображения

Пример 2

введите сюда описание изображения

Мой код

a = input()
col = 2
i = 0
my_dict = {}
for i in range(len(a)):
    my_dict[a[i]] = 1
while i < len(a):
    if a[i] * col in a:
        my_dict[a[i]] += 1
        col += 1
    elif col > 2:
        i += col
    else:
        col = 2
        i += 1
for i in sorted(my_dict.items()):
    print(i[0], i[1])

Ответы (5 шт):

Автор решения: Tehnorobot

Я предложу свой вариант кода(без while). Он, мне кажется, проще:

a = input()

my_dict = {}

for i in range(len(a)):
    my_dict[a[i]] = 1
count = 1
for i in range(len(a) - 1):
    if a[i] == a[i + 1]:
        if my_dict[a[i]] <= count:
            my_dict[a[i]] += 1
        count += 1
    else:
        count = 1 
print(my_dict)

for i in sorted(my_dict.items()):
    print(i[0], i[1])
→ Ссылка
Автор решения: GrAnd

Если не брать в расчёт, что выбран довольно странный алгоритм для довольно простой задачи, то ошибка именно в вашем коде в том, что i = 0 должно стоять не перед циклом for, а после него, непосредственно перед циклом while. Ибо цикл for испортил вам её и цикл while сработал всего раз только для последнего символа.

Вторая ошибка в том, что col = 2 стоит в блоке else, где оно смысла не имеет, т.к. col там и так равен 2. А вот в блоке elif эта строка как раз необходима, иначе col застрянет на большом значении, и вы начнёте проскакивать другие последовательности.

Ну и третья ошибка - надо проверять только уникальные буквы. Или каждый раз сбрасывать счётчик. Иначе насуммируется лишнего.

В общем, если придерживаться вашей задумки, то код, по идее, можно представить как-то так:

a = "bee gees"
#a = "correct your mistakes"
#a = "fooooooo baaar foo"
col = 1
my_dict = {}
i = 0
while i < len(a):
    if a[i] * col in a:
        my_dict[a[i]] = col
        col += 1
    else:
        i += 1
        col = 1
for i in sorted(my_dict.items()):
    print(i[0], i[1])
→ Ссылка
Автор решения: 0dminnimda

Что делает цикл for?

Он итерируется по объекту и присваивает значения элементов в переменную:

for i in 1, 2, 3, 4, 5:
    print(i)
print(i)

Выведет:

1
2
3
4
5
5

Вы, видимо, подумали, что значение i = 0, которые вы присвоили до цикла, останется и после него, но в вашем первом цикле вы изменяете значение i на индексы строки, потому после цикла значение i == len(a) - 1

Ок, исправляем, переносим i после цикла:

a = input()
col = 2
my_dict = {}

for i in range(len(a)):
    my_dict[a[i]] = 1

i = 0
while i < len(a):
    if a[i] * col in a:
        my_dict[a[i]] += 1
        col += 1
    elif col > 2:
        i += col
    else:
        col = 2
        i += 1

for i in sorted(my_dict.items()):
    print(i[0], i[1])

Проверяем приведённых значениях, вроде работает, а что если сделать не два, а три или более повторяющихся элементов .. не работает

Проверка того, что впереди есть такая последовательность

В строке a[i] * col in a вы пытаетесь понять, существует ли последовательность символов такой длинны впереди, а проверяете, существует ли такая последовательность во всей строке:
Есил ввести "ataaa", то вот, что произойдёт:
(мы уже инициализиировали dict и в нём уже лежит {"a": 1, "t": 1})

if a[i] * col in a:, проверяем

i == 0
a[i] == "a"
col == 2
a[i] * col == "aa"

следовательно "aa" in a == True, потому, что в a есть "aa", хоть не в начале.

Ок, давайте исправим, используем срезы:

if a[i: i+col] == a[i] * col:

a[i: i+col] - это срез с индекса i до i+col, не включая, пример:

если a == "abcdef", i == 3, col == 2, то с той нашей строкой у нас будет a[i: i+col] == "de"

Ок, заменяем: if a[i] * col in a: на if a[i: i+col] == a[i] * col: (Проверяем, что все буквы в срезе - те, что нам нужны)

Смотрим, что если ввести "ataaapppp", опять не то считает ...

Несколько длинных последовательностей

Логика таква, если есть последоательность такой длины, то мы задаём её, когда ма нашли конец последоательности, мы перезапускаем процесс, прасваивая col = 2, и перескакиваем к концу последовательности, , если же мы не находили последовательности, то просто идём дальше, и вот проблема, вы перескакиваете не к концу, а на один символ дальше, а также перепутали места, где мы перезапусчкаем процесс, исправляем:

elif col > 2:
    i += col - 1
    col = 2
elif col == 2:
    i += 1

Такс, проверяем, вроде работает, а есди использовать "ataaappppaaaaaaa", опять проблема, теперь с "a"

Несколько одинаковых последовательностей

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

my_dict[a[i]] += 1

на

if my_dict[a[i]] < col:
    my_dict[a[i]] = col

Результат

В итоге у нас получается что-то такое:

a = input()
col = 2
my_dict = {}

for i in range(len(a)):
    my_dict[a[i]] = 1

i = 0
while i < len(a):
    if a[i: i+col] == a[i] * col:
        if my_dict[a[i]] < col:
            my_dict[a[i]] = col
        col += 1
    elif col > 2:
        i += col - 1
        col = 2
    elif col == 2:
        i += 1

for i in sorted(my_dict.items()):
    print(i[0], i[1])

Альтернативы

Это далеко не лучший или не самый просто способ рещить эту задачу, вот идейка, как бы реализовать это лучше:

Идти по строке, и запоминать, какой был последний символ, и как долго он повторяется:

string = input()
max_lengths = {}
sequence_length = 1
latest_symbol = None

for char in string:
    if latest_symbol != char:
        sequence_length = 1

    if max_lengths.get(char, 0) < sequence_length:
        max_lengths[char] = sequence_length

    sequence_length += 1
    latest_symbol = char

for i in sorted(max_lengths.items()):
    print(*i)
→ Ссылка
Автор решения: Stanislav Volodarskiy

Другие участники уже указали на ошибки в коде и предложили рабочие решения. Я расскажу как решать задачу специфическими средствами Питона.

Прежде всего у нас есть строка (последовательность символов) и её надо разбивать на группы одинаковых символов. itertools.groupby решает эту задачу:

for k, g in itertools.groupby('abaa'):
    print(k, g)
a <itertools._grouper object at 0x7f6b9ba171f0>
b <itertools._grouper object at 0x7f6b9ba17e20>
a <itertools._grouper object at 0x7f6b9ba171f0>

Со значением g надо поработать. Это объект, который итерируется по значениям группы. Нам значения не нужны, только их количество. В Питоне нет нужной функции, приготовим сами: sum(1 for _ in g):

for k, g in itertools.groupby('abaa'):
    print(k, sum(1 for _ in g))
a 1
b 1
a 2

Длины групп соберем в словарь, который для каждой встреченной буквы будет хранить максимальную длину. d.get(k, 0) возвращает d[k] если оно есть или ноль иначе. sum вы уже знаете. d[k] = max... обновляет максимум в словаре:

d[k] = max(d.get(k, 0), sum(1 for _ in g))

Когда словарь готов, его надо отсортировать (не сам словарь, а данные из него) и напечатать. sorted упорядочивает пары по ключу-букве. f'{k} {v}' печатает одну запись. print(*..., sep='\n') печатает записи в разных строках:

print(*(f'{k} {v}' for k, v in sorted(d.items())), sep='\n')

Соберем всё вместе:

import itertools


d = {}
for k, g in itertools.groupby(input()):
    d[k] = max(d.get(k, 0), sum(1 for _ in g))
print(*(f'{k} {v}' for k, v in sorted(d.items())), sep='\n')
$ echo "correct your mistakes" | python longest_runs.py 
  1
a 1
c 1
e 1
i 1
k 1
m 1
o 1
r 2
s 1
t 1
u 1
y 1
→ Ссылка
Автор решения: GrAnd

Ну и решение в одну строчку для гиков :)

import re

print(*map(" ".join, map(lambda x: map(str, x), dict(sorted((x[0][0], len(x[0])) for x in re.finditer(r"((.)(\2)*)", a))).items())), sep="\n")

#или
#print(*map(lambda x: " ".join(map(str, x)), dict(sorted((x[0][0], len(x[0])) for x in re.finditer(r"((.)(\2)*)", a))).items()), sep="\n")

#или
#print(*map(lambda x: f"{x[0]} {x[1]}", dict(sorted((x[0][0], len(x[0])) for x in re.finditer(r"((.)(\2)*)", a))).items()), sep="\n")

#или
#print(*map("{0[0]} {0[1]}".format, dict(sorted((x[0][0], len(x[0])) for x in re.finditer(r"((.)(\2)*)", a))).items()), sep="\n")
→ Ссылка