Розглянемо складну задачу. На сайті eolymp.com її складність — 55%, тобто більше половини програмістів, що за неї бралися, її не подолали, а кількість спроб розв’язку перевищує 14 тисяч. При цьому, якщо прочитати умову уважно — задача проста. Давайте розбиратися.
Задача «Слово чемпіон».
https://www.eolymp.com/uk/problems/330
Умова:
Дано деяке речення на невідомій мові. Назвемо слово у ньому чемпіоном, якщо воно є паліндромом і кількість літер у ньому максимальна. Літерами алфавіту у невідомій мові є літери латинського алфавіту та арабські цифри. Гарантується, що у реченні відсутні інші символи, крім літер, пропусків, розділових знаків та нелітерних дефіс (мінус) і апостроф.
Вхідні дані
Речення на невідомій мові.
Вихідні дані
Номер слова чемпіона.
Ліміт часу 0.5 секунди
Ліміт використання пам'яті 64 Mб
Перший приклад вхідних даних: Oo, it aaa is not bb.
Вихідні дані: 3
Другий приклад вхідних даних: Oo, it aaa issi not bbbbb.
Вихідні дані: 6
Звичайно, для початку необхідно розібратися з означеннями. Вікіпедія пише, що паліндром — це слово, число, набір символів, словосполучення або віршований рядок, що однаково читається в обох напрямках (зліва направо та справа наліво). У статті на вікі є купа прикладів паліндромів, в тому числі достатньо драматичних як то «Три психи пили Пилипихи спирт», але немає чіткої відповіді чи є паліндромом слово з однієї букви. ChatGPT каже, що однобуквене слово можна вважати паліндромом і тут з ним можна погодитися. Не питайте його про трьох випиваючих психів, в цьому питанні воно до смішного дурне.
З паліндромом визначились. Мовою Python визначити чи слово є паліндромом можна, наприклад, так:
word = 'abba'
print(word == word[::-1])
Тестові приклади підказують нам, що треба привести всі букви до єдиного регістру. Бо без цього слово 'abba' буде зараховане як паліндром, а слово 'Abba' — ні. Тому приводим весь текст до одного регістру, наприклад, зробимо всі букви маленькими. Треба враховувати, що об’єкт текстового типу в мові Python є іммутабельним, тобто його не можна змінити.
Відповідно, так робити не можна:
txt = 'Василь'
txt.lower()
А так — можна:
txt = 'Василь'
txt = txt.lower()
Наступний етап дослідження — розділові знаки. В реченні, згідно умови, є розділові знаки, і нам потрібно їх з речення вилучити. До розділових знаків належать: крапка, кома, крапка з комою, двокрапка, тире, три крапки, знак оклику, знак питання, лапки, дужки, скісна риска, абзац, проміжок.
Як багато! Звичайно, можна вилучати їх по черзі:
txt = txt.replace('.','')
txt = txt.replace(',','')
Але так довго. Тому варто пошукати алгоритм колективного вилучення розділових знаків. Нам допоможуть регулярні вирази. Ось як можна в один рядок вилучити з речення цілу купу розділових знаків:
txt = re.sub(r'[.,;:!?{}\[\]()"]', '', txt)
Ну і вишенька на нашому торті. В умові написано, що в реченні можуть бути нелітерний дефіс (мінус) і апостроф.
Тут важливо не полінуватися і дізнатися, що це таке — нелітерні знаки.
Вікіпедія не така вже і наукова, але простою людською мовою пише, що нелітерні орфографічні знаки — категорія знаків писемності, які не є літерами, але використовуються в написанні слів (тобто належать орфографії), а не розділяють слова (на відміну від знаків пунктуації, що належать до пунктуації).
Дефіс і апостроф ми повинні в нашій задачі рахувати як літери! Ми не можемо викинути з тексту дефіси, тому що вони можуть бути важливими для визначення паліндромності. Ось, наприклад два слова:
abba-abba
abbaab-ba
Перше — паліндром, друге — ні. Різниця — в місці дефісу.
Але якщо дефіс стоїть окремо, наприклад, обрамлений пропусками, то це вже не буква, а окрема частина речення. Приклад:
abba - abak bebebeb
Формально це вже тире, тобто знак пунктуації, а ми такі знаки з речення вилучаемо. Тому будемо вилучати дефіс лише в тому випадку, коли він буде в оточенні пропусків:
txt = re.sub(r' - ', ' ', txt)
Так само з апострофом. Він, згідно умови, може бути частиною слова, наприклад
abba'abba або abbaab'ba
або може бути окремим символом в реченні, тоді буде оточеним пропусками. Зідно умови наше речення на невідомій мові, може в цій мові існують такі конструкції:
abba ' abak bebebeb
Отже, для розв’язування даної задачі нам потрібно розібрати поняття нелітерних орфографічних знаків, або ілетрограм. Інакше ми не зможемо повністю зрозуміти умову.
В узагальненому вигляді, порада програмістам може бути традиційною: «Читайте умову уважно і цілком» :)
Варіант коду:
import re
txt = input()
txt = txt.lower()
txt = re.sub(r'[.,;:!?{}\[\]()"]', '', txt)
txt = re.sub(r' - | \' ', ' ', txt)
index_max = 0
len_max = 0
words = [x for x in txt.split()]
for index, word in enumerate(words):
if word == word[::-1] and len(word) > len_max:
len_max = len(word)
index_max = index + 1
print(index_max)