极客讲堂 - 数据结构与算法之美 - 深度和广度优先搜索,字符串匹配基础,Trie树,AC自动机,贪心算法,分治算法

本文深入探讨了深度优先和广度优先搜索算法,以及多种字符串匹配算法,包括BF、RK、BM、KPM和AC自动机。详细解析了各种算法的工作原理、优缺点及适用场景,为读者提供全面的算法理解和选择依据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

31 | 深度和广度优先搜索

1. 基于数据结构“图”的搜索算法,比较简单的有 深度优先 和 广度优先 搜索算法。适用于图不大的情况。

2. 广度优先用 队列 来实现。逐层遍历,每遍历一个结点,就放入队列。 

3. 深度优先用 栈 来实现。通过堆栈,一层一层递归下去。

4. 深度优先和广度优先搜索的时间复杂度都是 O(E),空间复杂度是 O(V)。

    E: 图结构里的边的数目。

    V: 图结构里的结点的数目。

 

32 | 字符串匹配基础(上)

1. 定义: 在字符串 A 中查找字符串 B,那字符串 A 就是主串,字符串B 就是模式串。

2. 字符串匹配算法,比较简单粗暴的方法是 BF 算法。 方式是:逐个逐个字母地比较主串和模式串。

    理论上的最坏情况,时间复杂度是 O(n*m)。 n: 主串长度;m: 模式串长度。

3. RK 算法效率要高不少。方式是:

(1) 求主串中每个子串的hash值,和模式串的hash值做比较。数字之间比较是非常快速的,所以模式串和子串比较的

效率就提高了。

(2) 计算hash值时,可以把字符串视为一个26进制数(26个英文字母),然后转成十进制数。这就能快速计算出hash值。

     而且,下一个子串的是可以根据上一子串的数值来快速计算出结果(有一个公式),不需要每个子串都完整算一次hash值。

     通过查表法,还能进一步提升计算hash值的效率。

     hash值相同的话,子串和匹配串就相等了。

(3) 这个方式要注意,这个26进制数转成10进制数时,容易出现溢出情况(匹配串很长的时候)。 这时可以修改计算hash值的算法:  将子串的各位字母视为数字然后相加,得出一个整数。

(4) 上面(3) 的方法会有hash冲突的情况。 冲突处理时,再做一次BF 算法匹配就好了。效率依然很高。

4. RK 算法整体的时间复杂度就是 O(n)。

 

33 | 字符串匹配基础(中) -- BM算法

1. BF 算法和 RK 算法在极端情况下(数据量很大)退化得比较严重,RK 算法需要用到哈希算法,而设计一个可以应对各种类型字符的哈希算法并不简单。

    为了支持大容量文本,文字多样的文本的搜索,需要BM算法。

2. BM算法方式是:

(1) 回归主串和模式串逐个字母比较的普通方式。

(2) 在模式串中某个字符与主串不能匹配的时候,将模式串往后多滑动几位,减少不必要的比较,提高效率。

      具体有两个规则:坏字符规则和好后缀规则

(3) 坏字符规则: 从模式串的末端往前做匹配,如果和主串不一致,那在不一致的字符就是坏字符(位于主串里的那个)。

      如果坏字符在模式串里不存在,就可以模式串向后滑动N位。(细节不讲了)

      如果坏字符存在,就交给好后缀规则来做。(其实不管是否存在,都要走好后缀规则)

(4) 好后缀规则:

      模式串和主串有M位是一致的,这M位子串就是好后缀。然后在模式串的前端查找第一个同样的好后缀。然后根据各种判断, 向后滑动N位。(细节不讲了)

(5) 坏字符规则和好后缀规则一起使用,然后取滑动位数较大的那个。 

(6) 坏字符规则要建立hash表来记录字符位置,消耗内存比较大,可以考虑不用它,只用好后缀规则。效率降低一点。

 

附加:

1. 需要查找,需要减少时间复杂度,应该想到什么?散列表。
2. 如果某个表达式计算开销比较大,又需要频繁的使用怎么办?预处理,并缓存。

 

34 | 字符串匹配基础(下)-- KPM算法

1. kpm算法的意义: 虽然效率不如bm算法,但是当前应用广泛,并且很著名

2. kpm算法方式是:

(1) 也是主串和模式串逐个字母比较的普通方式。

(2) 在模式串中某个字符与主串不能匹配的时候,将模式串往后多滑动几位,减少不必要的比较,提高效率。

    具体是:  根据模式串的最长可匹配后缀子串(与前缀子串做比较),来计算后滑几位。

(3) 可针对模式串,预先计算好这个后滑几位的参数,叫做next数组。

(4) next数组可以简单粗暴地计算,但效率很低。所以采用优化的方式计算。

    具体是:模式字符串对自身进行匹配, 在任一位置,能匹配的最长长度就是当前位置的next值。

3. 参考文章:

    kmp算法理解参考 https://mp.weixin.qq.com/s/g9oD-Sd5PFOEucDS2_F0bA

    next数组计算参考 https://blog.csdn.net/x__1998/article/details/79951598

 

35 | Trie树

1. Trie 树是一种解决字符串快速匹配问题的数据结构。

2.  时间复杂度是 O(k),k 表示要查找的字符串的长度。

    Trie 树比较耗内存,是一种空间换时间的思路。(每个结点都要存储一个从a到z的数组)

3. Trie 树不适合精确匹配查找(耗费空间),适合的是查找前缀匹配的字符串的需求。(做动态集合数据的查找)

 

36 | AC自动机

1. AC自动机是基于 Trie 树的多模式串匹配算法,为了快速在主串中查找多个模式串。

2. 它跟 Trie 树的关系,就像单模式串中,KMP 算法与 BF 算法的关系一样。

    KMP 算法中有一个非常关键的 next 数组,类比到 AC 自动机中就是失败指针。

    AC 自动机失败指针的构建过程,跟 KMP 算法中计算 next 数组极其相似。

3. AC 自动机其实就是 KMP 算法在多个模式串上的改造。

附加:

1. BF: 简单场景,主串和模式串都不太长, O(m*n)
2. KP:字符集范围不要太大且模式串不要太长, 否则hash值可能冲突,O(n)
3. BM:模式串最好不要太长(因为预处理较重),比如IDE编辑器里的查找场景; 预处理O(m*m), 匹配O(n), 实现较复杂,需要较多额外空间.
4. KMP:适合所有场景,整体实现起来也比BM简单,O(n+m),仅需一个next数组的O(n)额外空间;但统计意义下似乎BM更快,原因不明.

 

37 | 贪心算法

1. 贪心算法的核心将要解决的问题抽象成贪心算法模型。 

    第一步:定义限制值和期望值。

    第二部:找限制值相同请款下,贡献期望值最大的数据。

    第三部:找几个例子测试一下。不需要严格的数学推导证明。

2. 例子:

(1) 分糖果:每个孩子的贡献期望值相同,优先满足限制值最小的那个。

(2) 钱币找零:每种钱币带来的限制值一样,优先选取贡献期望值最大的纸币。

(3) 区间覆盖:每个区间的贡献期望值相同,优先满足限制值最小的那个。

(4) 用贪心算法实现Huffman压缩编码: 最常用的字母选用最小的编码。每个字母贡献期望值相同,优先选取限制值最小的字母。

 

38 | 分治算法

1. 分治算法分三步:

(1) 分解:将原问题分解成一系列子问题;

(2) 解决:递归地求解各个子问题,若子问题足够小,则直接求解;

(3) 合并:将子问题的结果合并成原问题。

2. 需要满足下面几个条件:

(1) 原问题与分解成的小问题具有相同的模式;

(2) 原问题分解成的子问题可以独立求解,子问题之间没有相关性,

(3) 具有分解终止条件

(4) 可以将子问题合并成原问题,而这个合并操作的复杂度不能太高

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值