SciTech-BigDataAIML-Algorithm-Heuristic启发式 最优化算法: KMP字符串匹配 + A*(star)+ Prim + Dynamic Planning动态规划 + Floyd(弗落伊得)最短路线
SciTech-BigDataAIML-Algorithm-Heuristic启发式 最优化算法
所有的Heuristic(启发式)算法 的 “精髓” 在于对“Context(上下文)”的精准“计算、估计和预测”;
每一种算法都有其最适用的场景,算法的设计、选取 应当适配 场景;
非常好的“斯坦福大学”计算机科学毕业生的网站
Amit Patelamitp@cs.stanford.edu
很好的游戏算法+编程网:
https://www.redblobgames.com/pathfinding/a-star/introduction.html
- KMP字符串匹配算法
- Dynamic Planning动态规划
- Dijkstra迪杰斯特拉算法
- A*算法
- Floyd(弗落伊得)最短路线算法
- Prim算法
KMP字符串匹配算法
def kmp_search(string, patt):
"""signature: 字符串匹配算法: 在<string>,搜索<pattern>"""
patt_len = len(patt)
cmp_len = len(string) - patt_len + 1
next = build_next(patt) # next数组的数值,代表"当前字符"匹配"失败"时,"可跳过"的"匹配字符个数".
i = 0 # string 的指针: 只增不减,同时 pattern 的指针还可以预先偏移比较,是KMP的精华
j = 0 # pattern 的指针
while i < cmp_len : # 注意: i 只增不减, KMP算法的精华
if string[i] == patt[j]:
# 字符匹配成功:
i+= 1 # string 指针前移一个
j+= 1 # pattern 指针前移一个
elif j > 0:
# 字符匹配失败: 之前有匹配成功的不只一个字符,next匹配时, 可跳过"上一次"匹配过的“那一部分”
j=next[j-1] # pattern 指针退一字符, 停在最长匹配的字符上; 跳过pattern的前面一些子串. KMP精华
else:
# 字符匹配失败: 第一个字符就失配,只将"string"指针前移一个字符
i+= 1 # string 指针前移一个字符.
if j== patt_len: # 匹配成功: 当指针 j 等于 pattern 长度
print(string)
print("%s%s" % (' '*(i-j), patt))
return i-j # 退出. return (i-j)
def build_next(patt):
"""
预先计算构造出Next数组: PMT(Partial Match Table, 部分匹配表)
用pdb 的step debug调试 build_next("ababcdabak"), 就对PMT的构造有最深刻的认知.
"""
# next数组的数值,代表"当前字符"匹配"失败"时,"可跳过"的匹配字符个数".
prefix_len = 0 #当前共同"前后缀"的长度
next = [0] #next数组,初始时第一个元素的0
k=1
while k< len(patt):
if patt[prefix_len] == patt[k]:
prefix_len+=1
next.append(prefix_len)
k+=1 # k 前移一个字符
else:
if prefix_len==0:
# 前一个字符不同;
next.append(0)
k+=1 # k 前移一个字符
else:
# **k不变**,**只改变 prefix_len**, 可能经过好几次的iteration, 才能得出要插入next数组的最终数值.
# 当: k 由增加态, 首次转为0时,总之, 分两类情况:
# prefix_len=1, 例如 pattern = "ABCBAK",
# 当k=5时, 先prefix_len=1, 当前k位"反溯 prefix_len 个字符"的 "AK", 与 头部的 "AB"的"偏移"同;
执行next step后, 有prefix_len=next[0]=0,
# prefix_len>1, 例如 pattern = "AACAAK",
# 当k=5时, 先prefix_len=2, 当前k位"反溯 prefix_len 个字符"的 "AAK", 与 头部的 "AAB"的"偏移"同;
执行next step后, 有prefix_len=next[1]=1
prefix_len=next[prefix_len-1] # KMP的精华;
return next
s = "ABABABCAA"
p = "ABABC"
def print_next(patt):
print(build_next(patt))
# 用pdb 的step debug调试 build_next("ababcdabak"),
# 就对 next数组(PMT)的构造有最深刻的认知.
# In [9]: print_next("ababcdabak")
# [0, 0, 1, 2, 0, 0, 1, 2, 3, 0]
KMP 字符串匹配算法:
- KMP算法的时间复杂度为$ O(n+m)$
- 源于 Knuth, Morris, Pratt 三位大神的一篇论文"
FAST PATTERN MATCHING IN STRINGS".


BFM(Brute Force Matching)
先引入BFM(Brute Force Matching, 暴力匹配):
- BFM算法的时间复杂度为$ O(n * m)$
- 即在<str>搜索<pattern>,
由第一个字符开始一个个字符的与<pattern>比较,完全匹配上则return;
如果不完全匹配,则跳到下一个字符,重新一个个字符与<pattern>比较。
直到比较完成<str>的所有可能。

KMP( KMP Fast Pattern Matching)
KMP 快速匹配算法的思路是,不用BFM算法的"backup(回退)":
在匹配某一个字符时,
既然字符串在比对失败的时候,我们已经知道都读取比对过哪些字符序列,
有没有可能避兔“backup(回退)到下一个字符,重新匹配”的步骤?

KMP 匹配实例:
假设"string"为"ABABABCAA", 查找的"pattern"为"ABABC":
KMP匹配可能的最大长度字符串时: (i, j)指针对, 历经匹配的(0,0), (1,1), (2,2), (3,3),
![]()
![]()
![]()
KMP 匹配某一个字符, 字符串在比对失败时:
到(i, j) 为 (4,4) 时,"pattern"出现第一个“不匹配字符”, 此时 j = 4,
![]()
设置pattern头部"偏移": j=next[j-1], 偏移量可能值的情况是
- j = 0, 当 都可能将"j"设置为0,即对 string 的 i 处的字符与 pattern 的首个字符开始,一一比较.
- 0 < j < n, 当 pattern为一个字符重复出现 n次时, j 取得最大值:n-1
本例是 j=next[j-1]=next[3]=2
此时 j = 2, 同时 i=4(i不变)注意: 整个查找过程, i都是只向前移动,而pattern头部的“偏移量”根据"匹配情况"动态设置为[0, n)
这是 KMP算法的两个最大特点。
![]()
KMP 匹配某一个字符, 可以只 "Partial matching"(上一步比较过, 并且有Partial matched)跳过matched的部分:
![]()
在本例:- 即"AB"已经在上一次时匹配过的LCS(Longest Common Substring, 最长匹配substr),本次可以跳过Partial;
- 跳过"上一次匹配"过的"Partial matched", 是通过设置"本次匹配"的"pattern头部"的"偏移量"实现(string指针不变).
- 实现上: 由pattern预先build的next数组, 取出"本次匹配"可"预先跳过比较"的"最长pattern字符数".
- 源码:此时 string 指针 i 不变, 只要 pattern 指针设置成
j=next[j-1]( 因为j>0).
![]()
Papers: 下载 Knuth/Morris/Pratt 的Paper论文:
ACM(Association for Computing Machinery) of the USA.
https://dl.acm.org/doi/abs/10.1137/0206024
多读和写论文绝对有好处:
![]()
Dynamic Planning动态规划
Dynamic Planning/Programming:
动态规划是计算机解决最优化问题的一种方法; 他给我们的印象是效率高、速度快。
首先我们来看一个经典的“动态规划问题”:
给一个无序数组,找出所有"最长递增子序列":
举例: 无序数组$ nums=[1,5,2,4,3] $ 的 最长递增子序列: 一个是$ [1,2,4] \(, 另一个是\) [1,2,3] $
![]()
我们可以进一步简化这个问题:
只要算法求出"最长递增子序列"的长度就好;枚举(普通解法):
- 试验+探索:枚举代表性的一组数据(cases), 画出其"Recursion Tree":
![]()
- 理论设计: 写出其"Recursion Function", 用"科学方法"在"理论上"评估算法性能(时间复杂度, BigO Notion)":
![]()
![]()
![]()
- 试验+探索:枚举代表性的一组数据(cases), 画出其"Recursion Tree":
理论优化:
Pruning(剪枝)
![]()
![]()
![]()
记忆化搜索:
![]()
![]()
![]()
![]()
![]()
![]()
![]()
工程优化,将Recursion Method改写成 Iteration Method方式:
Iteration Method可以 释放对 Stack memory的占用,将"动态的内存需求"调整到用Heap memory满足:
![]()
最终评估: 用"科学方法"在"理论上"评估算法性能(时间复杂度, BigO Notion)"
![]()
扩展:
![]()
A *(Star) Algorithm(A星算法):
amitp@cs.stanford.edu
很好的游戏算法+编程网:
https://www.redblobgames.com/pathfinding/a-star/implementation.html
Loss Function: TotalCost="NewCost + PredicativeCost"
计算"总体的Cost": 包括一部分的"NewCost(已用成本)",和另一部分的"Predicative(预测成本)";
在对"predicative future cost(预测的将来成本)"的估计,和评估 TotalCost(总体成本)这些方面,
A *(Star) Algorithm(A星算法) 要优于 只计算 best next cost的Dijkstra(迪杰斯特拉算法)。
这是 A *(Star) Algorithm 多数时间 优于 Dijkstra Algorithm 的 root cause;
但是 Dijkstra Algorithm 的计算量小、算法精简。
| 1解决游戏的自动路线规划 | 2算法图示 | 3对比多种 |
|---|---|---|
![]() |
![]() |
![]() |
主体实现
def heuristic(a, b):
# Manhattan distance on a square grid
return abs(a.x - b.x) + abs(a.y - b.y)
def a_star_search(graph,start,goal):
frontier=PriorityQueue()
frontier.put(start,0)
came_from = {start:None}
cost_so_far ={start:0}
while not frontier.empty():
# 由"优先队列"抽取出"总代价最低"(new_cost+heuristic(goal,next))的node
current=frontier.get()
if current= goal:
break
for next in graph.neighbors(current):
new_cost = cost_so_far[current] + graph.cost(current,next)
if next not in cost_so_far and new_cost < cost_so_far[next]:
came_from[next]=current
cost_so_far[next] = new_cost
# 将next的node及其"总代价"插入"优先级队列"
frontier.put(next, new_cost+heuristic(goal,next))
return came_from, cost_so_far






Floyd(弗落伊得)最短路线算法
Prim算法
SciTech-BigDataAIML-Algorithm-Heuristic启发式 最优化算法: KMP字符串匹配 + A*(star)+ Prim + Dynamic Planning动态规划 + Floyd(弗落伊得)最短路线的更多相关文章
- Luogu 3375 【模板】KMP字符串匹配(KMP算法)
Luogu 3375 [模板]KMP字符串匹配(KMP算法) Description 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来 ...
- 洛谷—— P3375 【模板】KMP字符串匹配
P3375 [模板]KMP字符串匹配 题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next. (如 ...
- 洛谷P3375 [模板]KMP字符串匹配
To 洛谷.3375 KMP字符串匹配 题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next.如果 ...
- P3375 【模板】KMP字符串匹配
P3375 [模板]KMP字符串匹配 https://www.luogu.org/problemnew/show/P3375 题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在 ...
- KMP字符串匹配 模板 洛谷 P3375
KMP字符串匹配 模板 洛谷 P3375 题意 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next.(如果 ...
- {Reship}{KMP字符串匹配}
关于KMP字符串匹配的介绍和归纳,作者的思路非常清晰,推荐看一下 http://blog.csdn.net/v_july_v/article/details/7041827
- 洛谷P3375 - 【模板】KMP字符串匹配
原题链接 Description 模板题啦~ Code //[模板]KMP字符串匹配 #include <cstdio> #include <cstring> int cons ...
- P3375 模板 KMP字符串匹配
P3375 [模板]KMP字符串匹配 来一道模板题,直接上代码. #include <bits/stdc++.h> using namespace std; typedef long lo ...
- KMP字符串匹配学习
KMP字符串匹配学习 牛逼啊 SYC大佬的博客
- Java实现 蓝桥杯 算法提高 字符串匹配
试题 算法提高 字符串匹配 问题描述 给出一个字符串和多行文字,在这些文字中找到字符串出现的那些行.你的程序还需支持大小写敏感选项:当选项打开时,表示同一个字母的大写和小写看作不同的字符:当选项关闭时 ...
随机推荐
- 【记录】Opencv+LibTorch安装
环境Ubuntu20.04. [Opencv]源码编译:Linux系统下opencv3.4.1安装教程 [LibTorch]下载已编译版本:在Ubuntu下安装LibTorch [磁盘空间不足]vmw ...
- 高性能深度学习推理引擎 -- OpenPPL
OpenPPL OpenPPL是商汤基于自研高性能算字库的开源深度学习推理平台,能够让人工智能应用高效可靠地运行在现有的CPU/GPU等计算平台上,为云端场景提供人工智能推理服务 OpenPPL基于全 ...
- 操作系统:设备I/O -- 设备如何处理内核I/O包
上一讲实现了建立设备的接口,相当于制定了部门的相关法规,只要遵循这些法规就能建立一个部门.一个部门的职责不难确定,它应该能对上级下发的任务作出响应,并完成相关工作,而这对应到设备,就是如何处理内核的I ...
- AI模型的回调能力的理解和实现
前言 BigTall最近把RAG和Agent的原理想通了,对于"一切都是提示词"的理解又更多了一些.本文把我的理解大致整理了一下,给出BigTall自己的一个实验.希望能够对大家有 ...
- Got bad greeting from SMTP host: smtp.163.com, port: 465, response: [EOF]
在Spring Boot项目中,使用org.springframework.mail.javamail.JavaMailSender发送邮件抛异常,异常信息: Mail server connecti ...
- 记录一次自己用 AI 写IOS APP的经历
我是几乎没有移动端开发经验的.仅有的一点安卓开发经验还是十几年前没毕业的时候自己瞎折腾. 故事的起源是每天辅导我儿子功课时的暴跳如雷. 我儿子上一年级了,在语文的生词上落后得非常严重(当然可能是他同学 ...
- 解决DevToolsActivePort file doesn't exist
今天遇到个小问题:selenium 启动 chrome crash,报错:DevToolsActivePort file doesn't exist. 在option中添加一下几行: option = ...
- c#格式化字符串 toString()
1.使用 ToString 方法的默认格式设置 public class Automobile { public string Name { get; set; } = "小王"; ...
- 「Log」2023.8.25 小记
序幕 到校同学都没来,先摆. 写博客,写啊,写啊. 改费用流板子. \(\color{royalblue}{P3381\ [模板]最小费用最大流}\) 板子. 痛心疾首,建边的时候费用边反边为负权边. ...
- Go标准库Cond
Go标准库的Cond Go 标准库提供 Cond 原语的目的是,为等待 / 通知场景下的并发问题提供支持.Cond 通常应用于等待某个条件的一组 goroutine,等条件变为 true 的时候,其中 ...




























