Тёмный

Алгоритм Кнута-Морриса-Пратта 

Roman Tsarev
Подписаться 2,9 тыс.
Просмотров 74 тыс.
50% 1

Алгоритм Кнута-Морриса-Пратта (алгоритм КМП) - это один из классических алгоритмов поиска образа в строке или, проще говоря, поиска слова или фразы в тексте. Эффективность алгоритма проявляется при частичном совпадении символов образа и строки. В этом случае, при несовпадении символов в дальнейшем сдвиг образа вдоль строки происходит не на один символ, как при прямом поиске, а дальше.
1. Прямой поиск vs КМП 0:28
2. Создатели алгоритма КМП 1:50
3. Первый этап алгоритма КМП 2:34
3а. Префикс и суффикс 3:01
3б. Формирование массива сдвига 7:10
3в. Программная реализация 9:45
3г. Псевдокод 14:59
4. Второй этап алгоритма КМП 15:50
4а. Поиск образа в строке 15:58
4б. Программная реализация 19:29
4в. Псевдокод 23:44
5. Сложность алгоритма КМП 25:18

Опубликовано:

 

28 май 2024

Поделиться:

Ссылка:

Скачать:

Готовим ссылку...

Добавить в:

Мой плейлист
Посмотреть позже
Комментарии : 110   
@prigl4548
@prigl4548 4 года назад
С анимированными картинками гораздо понятнее чем псевдокод на лекциях или в книге с кучей определений. Спасибо! Подписался)
@romantsarev1145
@romantsarev1145 4 года назад
Пожалуйста!
@tayzlelavarez6848
@tayzlelavarez6848 Год назад
вот именно. потому что на лекциях и в книге надо напрячь мозги и УВИДЕТЬ, что тут можно провернуть хитрость и выиграть в скорости, не делая лишних действий. а в видео тебе УКАЗЫВАЮТ, что вот она хитрость. да и в этом видео, только половину хитрости при поиске показали, остальную хитрость при быстрейшем заполнении pi-массива тихонько утаили, сразу реализацию выдав.
@romantsarev1145
@romantsarev1145 Год назад
@@tayzlelavarez6848 Да куда уже подробнее то?!
@tayzlelavarez6848
@tayzlelavarez6848 Год назад
@@romantsarev1145 да лан, нормально. спасибо.
@Nik-qp1px
@Nik-qp1px 5 лет назад
Спасибо за информацию. Особенно порадовала часть про программную реализацию. Объяснения ещё детальнее пока не встречал
@romantsarev1145
@romantsarev1145 5 лет назад
Пожалуйста. Я старался.
@DAIMON-tf8xd
@DAIMON-tf8xd 5 лет назад
Огромное спасибо!!! Это самое лучшее объяснение в моей жизни. Продолжаете еще
@innokent9985
@innokent9985 5 лет назад
Наконец-то врубился, очень хорошо об'яснил, до этого безуспешно пытался самостоятельно понять метод по книге Н.Вирта Алгоритмы и структуры данных. Спасибо! С наступившим!
@romantsarev1145
@romantsarev1145 5 лет назад
Та же история с Виртом ) Пожалуйста!
@fedormaximoff6587
@fedormaximoff6587 2 года назад
Три года назад ты сделал видео, а сегодня я весь день пытался разобраться с алгоритмом, а понял только сейчас. Спасибо!
@romantsarev1145
@romantsarev1145 2 года назад
Супер! Рад, что помог.
@nadyamoscow2461
@nadyamoscow2461 3 года назад
Огромное спасибо. Более подробно объяснить невозможно. Вы лучший.
@rabdude
@rabdude 4 дня назад
Спасибо огромное!
@romantsarev1145
@romantsarev1145 3 дня назад
Пожалуйста
@TheBogdanLisichenko
@TheBogdanLisichenko 3 года назад
Ты просто царь. Реально четко все сделал, слайды сделал заморочился, молодец, внатуре чотко +.
@shameoff16
@shameoff16 2 года назад
Не зря это видео в рекомендациях гугла первое. Действительно самый понятный урок из тех, что смотрел
@romantsarev1145
@romantsarev1145 2 года назад
Значит своей цели я достиг 😇
@synthwave_chad
@synthwave_chad 4 года назад
Всё по полочкам, максимально ясно, спасибо!
@evac6117
@evac6117 4 года назад
Спасибо за урок! Все понятно и просто, не каждый сможет так. Лайк!
@romantsarev1145
@romantsarev1145 4 года назад
Спасибо. Очень приятный отзыв!
@sherzodnurjonov5459
@sherzodnurjonov5459 3 года назад
Thanks Roman, it was the best explanation I've ever seen!
@azamat1bakhov
@azamat1bakhov 5 лет назад
Чувак, спасибо большое.
@pavellyakh5598
@pavellyakh5598 4 года назад
Отличное объяснение! Спасибо!
@solidesuu
@solidesuu 2 года назад
Большое спасибо за такое понятное и подробное объяснение!
@romantsarev1145
@romantsarev1145 2 года назад
Пожалуйста!
@ultraon83
@ultraon83 2 года назад
Спасибо большое, все четко, понятно и без лишнего!
@romantsarev1145
@romantsarev1145 9 месяцев назад
Пожалуйста
@user-dv8ly1vf3n
@user-dv8ly1vf3n Год назад
Большое спасибо!
@romantsarev1145
@romantsarev1145 Год назад
Пожалуйста!
@dmitriykuznetsov4464
@dmitriykuznetsov4464 5 лет назад
Большое спасибо! Стало понятно наконец!
@user-yx5mb4sz9t
@user-yx5mb4sz9t 2 года назад
Вот это уровень! Ролик и объяснение топовые. Молодец!
@romantsarev1145
@romantsarev1145 2 года назад
Спасибо!
@Funware
@Funware 2 года назад
Охх, вижу кто-то тоже прямо сейчас алгоритмы изучает :) Автор молодец, большое ему спасибо, тоже понял благодаря ему.
@alexandergaiwer9804
@alexandergaiwer9804 2 года назад
Отличный урок! Все очень наглядно и понятно! С меня подписка, а Вам и Вашему каналу желаю удачи!!!
@romantsarev1145
@romantsarev1145 9 месяцев назад
Спасибо
@IgraphyRupage
@IgraphyRupage 6 лет назад
Спасибо! Отличное видео! Подписался:)
@user-ey3kx3oi4j
@user-ey3kx3oi4j 2 года назад
Спасибо тебе, мил человек! Очень помог!
@romantsarev1145
@romantsarev1145 2 года назад
От всего сердца!
@glebbondarenko67
@glebbondarenko67 5 лет назад
Спасибо, все понятно
@asemanurzhankyzy9802
@asemanurzhankyzy9802 4 года назад
очень классное видео! объясняет просто и понятно
@romantsarev1145
@romantsarev1145 4 года назад
Я рад, что пригодилось
@user-bd2gj5fu3d
@user-bd2gj5fu3d 2 года назад
как же круто подано!) спасибо!
@romantsarev1145
@romantsarev1145 2 года назад
Пожалуйста!
@Km-pn3hf
@Km-pn3hf 2 года назад
эх, 2 года назад смотрела для лаб в универе, а теперь готовлюсь к собеседованиям) ещё раз спасибо!
@romantsarev1145
@romantsarev1145 2 года назад
Пожалуйста
@specwnm
@specwnm 2 года назад
Спасибо большое, даже сейчас очень годно!
@romantsarev1145
@romantsarev1145 2 года назад
Нестареющая (с 1967 года) классика!
@arturians
@arturians 3 года назад
Спасибо за видео! После прочтения статей не сложилось общей картины, но благодаря вашему видео всё улеглось!
@romantsarev1145
@romantsarev1145 3 года назад
Пожалуйста!
@user-ef3bt9ni4o
@user-ef3bt9ni4o 3 года назад
Спасибо, медленно и последовательно, как раз для таких нубов как я! Спасибоооо!!!)
@romantsarev1145
@romantsarev1145 9 месяцев назад
Пожалуйста!
@IharShkilionak
@IharShkilionak 5 лет назад
respect & appreciation
@romantsarev1145
@romantsarev1145 5 лет назад
Nice!
@marines8725
@marines8725 2 года назад
большое спасибо!
@romantsarev1145
@romantsarev1145 9 месяцев назад
Пожалуйста
@supercelt3
@supercelt3 4 года назад
Классное объяснение, спасибо) только я не допонимаю, что будет если уже на 1 символе строка и подстрока не равны, и образ весь при этом по нулям в массиве ПИ
@addmagtech
@addmagtech 3 месяца назад
Просто поразительно! Нет-нет да и надо сказать вместо "в 1969-м году" - "в 1989-м году". В инете сплошь и рядом! Когда на картинке не нарисовано, или проверить нельзя то туго приходится...😉
@romantsarev1145
@romantsarev1145 3 месяца назад
Оговорился, когда записывал. Правильно, как на слайде, 1969. Перезаписывать не стал, потому-что на тот момент звук выстроить не смог бы. Однако, если Вы так внимательно слушали, то должны были заметить, что я подчеркиваю, что Матиясевич продолжил этот алгоритм ранее Кнута, Морриса и Пратта. А они это сделали в 1970, опубликовали в 1977. Так что 1989 однозначно отпадает. 🎉
@tornem23
@tornem23 6 лет назад
Большое спасибо за видео. Помогло разобраться. Но единственное, хотелось бы видеть переход от наивной реализации скажем той же префикс-функции к уже эффективной, чтоб было понятно как от вашего теоретического описания мы пришли вот к такой реализации, но это ИМХО, возможно только мне был непонятен этот момент с наскока =) А так, огромное спасибо
@romantsarev1145
@romantsarev1145 6 лет назад
За видео пожалуйста. Ваш вопрос не понял. В ролике я сначала даю общее описание этапа, а следом его же программную реализацию. Например, в общем описании - последовательно переберем все символы образа, а в последующем описании программной реализации - возьмем целочисленную переменную i, у которой будут меняться значения от 0 до N-1, где N - количество символов в образе. То есть ничего не убавляю и не добавляю, а показываю как программно реализовать то, о чем только что рассказывал.
@user-rg9mb3hl6y
@user-rg9mb3hl6y 5 лет назад
Великолепно, намного понятнее чем в шараге
@romantsarev1145
@romantsarev1145 5 лет назад
Спасибо. А что такое шарага?
@user-tr6tp5qy7y
@user-tr6tp5qy7y 5 лет назад
Здравствуйте, спасибо за видео. Шарагой называют место для получения среднего профессионального образования)
@user-rg9mb3hl6y
@user-rg9mb3hl6y 5 лет назад
@@user-tr6tp5qy7y в данном случае я иронично назвал шарагой место для получения высшего образования
@Km-pn3hf
@Km-pn3hf 4 года назад
спсибо!
@romantsarev1145
@romantsarev1145 4 года назад
Пожалуйста!
@pklgn
@pklgn 2 года назад
Спасибо за видео. После просмотра остался вопрос: можно ли в данной реализации отследить отсутствие подстроки в строке, если основная строка закончилась раньше, чем мы успели обработать подстроку? Например для подстроки AC и строки AAA мы не попадём в условие "...если k=m, то образа в строке нет", потому что, как я понимаю, переменная l будет равна 1.
@romantsarev1145
@romantsarev1145 2 года назад
Здравствуйте! Покажет в любом случае, что образа в строке нет.
@repashka
@repashka 2 года назад
Спасибо
@romantsarev1145
@romantsarev1145 2 года назад
Пожалуйста
@user-gs5cr8lp3l
@user-gs5cr8lp3l 5 лет назад
Самое доходчивое объяснение из тех, что доводилось читать или видеть, буду рекомендовать ваше видео на профильных каналах и ресурсах. Есть задача - нужно найти в строке все вхождения: string = "banana", substring = "ana" При прямом поиске отлично находит оба вхождения: bANAna и banANA Но поскольку максимальная длинна строки может достигать 10 в 6 степени, это происходит крайне медленно и нужно ускорить. Применяем КМП (если взять реализацию на Python по ссылке товарища @UCZCeENC0VU4nX8wCj--kikA) и тут возникает "НО", находится только одно первое bANAna :-0 По идее при нахождении вхождения нужно воспользоваться префикс функцией с последним индексом P [-1] и начать поиск следующего вхождения с этой позиции: текущая - P [-1] Возможно, есть какой-то другой алгоритм, более подходящий для этих целей в указанных условиях. P.S. Реализацию могу выложить на пайтон, если нужно.
@romantsarev1145
@romantsarev1145 5 лет назад
Искать первое вхождение или все - зависит от постановки задачи и, в общем-то, от программиста, а не алгоритма КМП. При этом еще нужно определиться, как считать вхождения. Например, сколько вхождений образа "aa" в строке "aaaa", два или три? Насчет программы на Python, на Ваше усмотрение.
@user-gs5cr8lp3l
@user-gs5cr8lp3l 5 лет назад
@@romantsarev1145 Если нужно найти ВСЕ вхождения и нет дополнительных условий, наверное, нужно искать все вхождения :) Что бы ответить на вопрос сколько "аа" входит в строку "аааа" можно запустить прямой поиск и он даст однозначный ответ (AAaa ,aAAa, aaAA), странно, если КМП выдаёт что-то другое ИМХО. К КМП нужно было обратиться, чтобы снизить сложность с O(m*n) при прямом поиске до O(m+n) при КМП.
@kotokotfgcscrub
@kotokotfgcscrub 5 лет назад
вроде правильно работает поиск пи функции от суммы подстроки и строки с разделителем(f(sub+'#'+s)), совпадения при значении равном длине подстроки, про скорость не могу сказать
@user-gs5cr8lp3l
@user-gs5cr8lp3l 5 лет назад
@@kotokotfgcscrub Они все правильно работают, вопрос только в реализации и конечно в сложности(скорость не совсем тот параметр, сильно зависит от входящих данных)
@user-ug5vf5vd7h
@user-ug5vf5vd7h 4 года назад
единственное нормальное объяснение алгоритма, везде какая то сложная каша, спасибо
@evgenii.v
@evgenii.v 2 года назад
Визуализация крутая, очень понятно, спасибо!
@romantsarev1145
@romantsarev1145 9 месяцев назад
Пожалуйста!
@guiterenzog2723
@guiterenzog2723 2 года назад
Спасибо за разбор! Понял логическое объснение, но на моменте с кодом возник вопрос: почему j = pi[j-1]? Не понимаю, почему это так работает
@belkevglaz
@belkevglaz 5 месяцев назад
У нас есть префикс для `s[i - 1]` равный `k = π[i - 1]`. Как длина он указывает сколько символов в макс префиксе `i - 1`, как индекс он указывает на символ, *следующий* за префиксом. На `i`-ой итерации мы "приписываем" символ справа к префиксу и суффиксу. Если символы одинаковые - всё просто - префикс увеличился на 1. Если разные, значит текущие префикс и суффикс не равны и отличаются только последнем символом (до этого же были равны). Тогда они могут перекрываться "кусочками" меньшей длины, т.е. иметь общий префикс/суффикс более короткий на отрезке `s[0, k)`. Откуда его взять? У нас есть старый `π[i - 1] = k` НОП, который указывает на следующий символ после НОП-а. Нам надо найти НОП в подстроке `s[0, k)` т.к. перекрытие "куском" будет именно там, поэтому берем `π[k - 1]` и сравниваем только последние символы. Т.е. если текущие префикс/суффикс не равны, мы берем НОП для подстроки предыдущего префикса, увеличиваем на символ и сравниваем с "куском" нового суффикса. Т.е. если `s[k] != s[i]` то `s[π[k - 1]] ?= s[i]`. И так до конца.
@Mr.SKIFLANDIAN
@Mr.SKIFLANDIAN 2 года назад
Есть идеи запилить полноценный курс по алгоритмам? Я например купил бы этот курс))))
@romantsarev1145
@romantsarev1145 2 года назад
Так, вроде, есть уже такие.
@user-fr8bm7do1j
@user-fr8bm7do1j 3 года назад
ромчик хорош
@index058
@index058 2 года назад
Правильно ли я понимаю, что этот алгоритм не найдёт подстроку "кукиш" в строке "кукукишка"?
@romantsarev1145
@romantsarev1145 2 года назад
Конечно, найдет. Вообще, идея алгоритмов этого класса - шагнуть как можно дальше при несовпадении, при этом, естественно, не пропустить вхождения образа в строку.
@musicits_fun
@musicits_fun Год назад
Честно сказать думал что ПИ-функция поможет вычислить все повторения в строке. Самое интересное, что в начале, когда используешь маленькую последовательность, он таки и работает. Но вот если вставить что-то навроде: "'qwertyqwerasdfghjklzxcvbnmcvbnmcvbnm'", то выдает только первые совпадения, а "cvbnm" повторяющийся в конце, уже не видит. Может быть кто-то подскажет алгоритм быстрый для поиска повторений в строке? реализовал алгоритм по здешнему пседокоду, думал с ним что-то не так, взял готовый из интернета и тот же результат.
@musicits_fun
@musicits_fun Год назад
не работает не из-за длинны, а просто алгоритм для моей задачи не предназначен :) Ну или я не вижу, как применить пока. Если даже взять пример из видео "abbaabbab" который выдает хороший результат и добавить просто любую не использованную дальше букву к примеру так "cabbaabbab", то всё становится нулями. Так и должно быть?
@musicits_fun
@musicits_fun Год назад
В общем, решил всё с помощью суффиксного дерева(Алгоритм Уконена). Оно вообще многое может, по сути мульти-решатель многих задач. Переделал с обработки символов, на обработку массива и теперь можно любой массив с данными выстроить в дерево и делать интересные вещи с этим массивом. Просто достаточно compare-функцию определить для обработки сравнения и всё. Всем советую! ;)
@MrAnonim2123
@MrAnonim2123 2 года назад
👍
@romantsarev1145
@romantsarev1145 9 месяцев назад
Thumbs up
@react_js
@react_js 3 года назад
02:15 Вы говорите в восемьдесят девятом году( 1989). Написано там 1969
@romantsarev1145
@romantsarev1145 3 года назад
1969 верно. Было уже не исправить.
@tayzlelavarez6848
@tayzlelavarez6848 Год назад
ничего не понятно. самое важное не пояснено, почему при заполнении pi-массива если совпадение, то значение на единицу больше чем j, и почему если несовпадение, то j получает значение предыдущего относительно j элемента pi (причем случай НЕсовпадения сильно сложнее для понимания, чем случай СОвпадения). из такого видео алгоритм все равно не понимается, лишь сама реализация уже наизусть сама по себе учится. то есть смысла от видео нет, невозможно будет воссоздать это решение самому потом, все кто "поняли", потом забудут решение и вернуться сюда снова. я уже третий или четвертый день не могу понять эту магию с j = pi [j - 1] и почему это работает. (на 5ый понял, слава богу).
@user-ks9gf1lc6l
@user-ks9gf1lc6l 2 года назад
Когда объясняете словесно все просто. Но когда начинаю разбираться почему именно так устроен псевдокод, то ломается мозг) К сожалению детально псевдокод не разобран, почему именно так все работает, а не иначе
@romantsarev1145
@romantsarev1145 2 года назад
Уж как мог 😇
@user-ks9gf1lc6l
@user-ks9gf1lc6l 2 года назад
@@romantsarev1145 спасибо вам! без этого объяснения так быстро бы не разобрался
@romantsarev1145
@romantsarev1145 2 года назад
@@user-ks9gf1lc6l Пожалуйста!
@benrise4775
@benrise4775 2 года назад
Что такое m?
@romantsarev1145
@romantsarev1145 2 года назад
Число символов в строке, т.е. в тексте, в котором ищем образ.
@user-ux7vy8fo3o
@user-ux7vy8fo3o 11 месяцев назад
Спасибо, наверное лучшее объяснение на русском языке.
@romantsarev1145
@romantsarev1145 11 месяцев назад
Спасибо
@86werth
@86werth 4 года назад
2:10 1969 год, а не 1989
@romantsarev1145
@romantsarev1145 4 года назад
Верно
@user-sh4zx5rs2l
@user-sh4zx5rs2l Год назад
ниасилил.. пойду спать
@romantsarev1145
@romantsarev1145 Год назад
Тут с наскока не взять. Особенно, если сонный. Так что высыпайся, а завтра со свежими силами... Ну, если что будет непонятно, пиши, проконсультирую.
@volodymyrmelnyk1590
@volodymyrmelnyk1590 3 года назад
не поняв нічо
@romantsarev1145
@romantsarev1145 3 года назад
А это, между прочим, самое понятное видео на русском об алгоритме КМП
Далее
Сортировка выбором
2:48
Просмотров 52 тыс.
Cosa è stato messo nel suo zaino?
00:37
Просмотров 3,6 млн
Алгоритм Дейкстры
12:07
Просмотров 155 тыс.
ADS1: Boyer-Moore basics
8:50
Просмотров 244 тыс.