Алгоритм был разработан Кнутом (Knuth) и Праттом (Pratt) и независимо от них Моррисом (Morris) в 1977 г.
Он относится к «правильным» подходам решения поставленной задачи, в отличии от тривиального подхода, рассмотренного ранее.
Данный подход хоть и считается достаточно тривиальным, описания, которые нашел я, зачастую пестрят математическими основами и доказательствами, которые сбивают с сути. Так в книге, уважаемого Никлауса Вирта, приводится описание, которое я так и не одолел.
Однако я нашел пару статей, которые достаточно информативны, они приведены в ссылках и рекомендуемы для ознакомления.
Для понимания: Префикс строки A[..i] — это строка из i первых символов строки A. Суффикс строки A[j..] — это строка из |A|-j+1 последних символов. Подстроку из Aбудем обозначать как A[i..j], а A[i] — i-ый символ строки.
В статье http://habrahabr.ru/post/111449/ сказано:
Идея КМП-поиска – при каждом несовпадении двух символов текста и образа образ сдвигается на все пройденное расстояние, так как меньшие сдвиги не могут привести к полному совпадению.
Многие люди ошибаются в этом пункте, считая, что не надо возвращаться назад, а можно продолжать обработку строки A с текущей позиции. Почему это не так легко продемонстрировать на примере поиска X=«AAAB» в A=«AAAAB». Первая гипотеза нас приведет к четвертому символу A: «AAAAB», где мы обнаружим несоответствие. Если не откатиться назад, то вхождение мы так и не обнаружим, хотя оно есть.
Для реализации данного алгоритма, нам необходимо рассмотреть, так называемую, префикс функцию.
Префикс-функция — это массив чисел, вычисляющийся, как наибольшая длина суффикса, совпадающего с её префиксом. Как пример, берем каждый возможный префикс строки и смотрим самое длинное совпадение начала с концом префикса (не учитывая тривиальное совпадение самого с собой).
Вот пример для «ababcaba»:
| суффикс | префикс | p |
|---|---|---|
| a | a | 0 |
| ab | ab | 0 |
| aba | aba | 1 |
| abab | abab | 2 |
| ababc | ababc | 0 |
| ababca | ababca | 1 |
| ababcab | ababcab | 2 |
| ababcaba | ababcaba | 3 |
Итак, идея ясна? Ну тогда попробум написать префикс функцию в лоб:
def predkompil(x):
#первый символ всегда 0, поэтому заносим и пропускаем
d = {0:0}
for i in xrange(1,len(x)):
# проходоим от конца к началу
j = i
sdvig = 0
while j>0:
j -= 1
if x[j] == x[i-sdvig]:
sdvig += 1
else:
j += sdvig
sdvig = 0
d[i] = sdvig
return d
Вроде работает, но как то много сравнений и проходов. Попробуем оптимизировать.
Начать можно с замены строки j = i, на j = d[i-1]+1.
Что нам это дает? А то, что незачем просматривать каждый раз с конца и до начала. Можно заметить, что если мы на предыдущем шаге (i-1) нашли вхождение > 0 (d[i-1]), то и начинать стоит с данной позиции (d[i-1]).
Пример:
При i=4 ABAAB -> 2, тогда на i+1, т.е. i=5 смотрим не с j=i(5), а с 3! Т.к. либо счетчик вырастет и станет 3 в случае ABAABA, либо сбросится в 0 при любой другой букве.
И хотя мы делаем меньше сравнений(пропускаем середину слова), однако весь совпадающий префикс мы проходим, что не есть хорошо.
Это уже не плохо, однако, мы с Вами так и не научились использовать информацию, полученную на предыдущих и
Тибетская диета
Тип диеты — низкокалорийная
Убыль веса — 3-4 кг
Продолжительность — 7 дней
Если вы хотите не только хотите похудеть, но и омолодить свой организм обязательно попробуйте тибетскую диету. Основа диеты – молоко и продукты растительного происхождения – овощи и фрукты. Мясо, птица, яйца запрещены. Исключение составляет рыба, которая присутствует в диете в незначительном количестве, да и то не каждый день.
Основные правили тибетской диеты:
— есть нужно не торопясь, в спокойной обстановке, тщательно пережевывая пищу, это способствует лучшему перевариванию и не дает откладываться жиру;
— перекусы между основными приемами пищи запрещены;
— питьевой режим не ограничен, но воду пить рекомендуется за час до еды, лучше родниковую или минеральную без газов;
— стараться не есть на ночь, последний прием пищи должен быть не позднее чем за два часа до сна;
— сочетать диету с дыхательными и физическими упражнениями на свежем воздухе, это способствует более эффективному похудению, а так же омоложению организма.
Использование try-finally
Хочу обратить внимание на маленькую особенность написания конструкции try-finally.
Возьмём для примера многопоточность, а конкретно блокировки.
Где-то (наверное, в конструкторе класса) мы создали объект блокировки:
self.locker = threading.RLock()
Затем в каком-то методе мы пытаемся использовать эту блокировку в try-finally statement. Да, я знаю что RLock поддерживает context manager protocol и может использоваться в with statement. Так будет даже лучше, но мы сейчас говорим о другом варианте использования.
try:
self.locker.acquire()
do_some_work()
finally:
self.locker.release()
В чём ошибка? .acquire() может выбросить исключение. Блокировка не будет захвачена и попытка её освободить в .release() выбросит новое (другое) исключение. Что крайне нежелательно. Особенно в python 2.x, где нет цепочек исключений. Т.е. ошибка в .acquire() будет просто скрыта, понять в чём было дело невозможно.
Правильно писать так:
self.locker.acquire()
try:
do_some_work()
finally:
self.locker.release()
Если было исключение в .acquire() — то блокировка не захвачена и освобождать её не нужно. Пусть обработка исключения разворачивается своим ходом, .release() в finally block совершенно не нужен.
Правило простое и понятное, тем не менее я сам нередко писал ошибочный код. А сегодня опять увидел это проблему при чтении чужих исходников.
Проблема усугубляется тем, что обычно .acquire() работает успешно, и лишь в редких случаях выбрасывает исключение. Которое мы видим в логах (все используют логи, верно?) и недоумеваем, что именно произошло.
Это замечание относится к любому коду, выполняемому в finally block.
Переменные, блокировки, захват ресурсов, открытие файлов и т.д. должны быть выполнены перед try.
P.S.
На открытие файлов хочу обратить особое внимание как на самый частый случай. Куда более частый чем работа с многопоточностью. Правильно писать:
f = open('filename')
try:
f.read()
finally:
f.close()
Надеюсь, последний пример запомнится хорошо и внесёт ясность в головы уважаемых молодых коллег.
Автор: Andrew Svetlov

Украшения легко и просто
Как нам хочется щеголять весной во всей красе, не уставая удивлять окружающих все новыми и новыми нарядами и аксессуарами. С наступлением весны мы все сами пробуждаемся, у нас находится куча дел. Нужно все время куда-то бежать, что-то делать и с кем-то договариваться. Когда найти время на рукоделие? А ведь на украшения хэндмэйд нередко нужно потратить немало времени, запастить терпением и усидчивостью. Так бывает часто, но не в этот раз. Сегодня мы представляем мастер класс для ленивых или очень занятых девушек. Бижутерия легко и просто, и, самое важное, быстро представляется вашему вниманию, дорогие читательницы.
batch resize, или массовое изменение размера картинок в Linux Debian/Ubuntu
Столкнулся с необходимостью быстро отресайзить папку фотографий. Так как под рукой только Linux Ubuntu, пришлось искать способы под него.
Конечно, была идея отресайзить все картинки через Гимп, но это стрельба из пушки по воробьям. Причём медленная стрельба.
А простой и красивый способ нашёлся следующий.
South. Документация. Конвертирование приложения
Конвертирование приложения
- Отредактируйте ваш settings.py и укажите south в INSTALLED_APPS (мы предполагаем, что Вы установили south туда, куда нужно)
- Запустите ./manage.py syncdb для того, чтобы загрузить таблицу South в БД. Обратите внимание, что теперь syncdb не такой как раньше — South его изменил
- Запустите ./manage.py convert_to_south myapp — South автоматически подготовит и выполнит первую миграцию
Конвертирование других установок и серверов
Автор: Ishayahu Lastov

