《算法图解》读书笔记(二)

第六章——图——广度优先搜索

1.解决最短路径问题(shortest-path problem)的算法被称为广度优先搜索(breadth first search)。

2.图由节点(node)和边(edge)组成,一个节点可能与众多节点直接相连,这些节点被称为邻居,图用于模拟不同的东西是如何相连的。

3.广度优先搜索(BFS)是一种用于图的查找算法,可帮助回答两类问题。第一类问题:从节点A出发,有前往节点B的路径吗?第二类问题:从节点A出发,前往节点B的哪条路径最短?

4.队列类似于栈,不能随机地访问队列中的元素,队列只支持两种操作:入队和出队,是一种FIFO数据结构,而栈是LIFO数据结构,队列可用于BFS。

5.散列表可用于实现图,并且散列表是无序的,添加键值对的顺序无关紧要。将散列表中的数据加入队列数据结构,实现BFS。

6.在Python中,可使用函数deque来创建一个双端队列。

from collections import deque

图中可能有一个节点同时是两个人的邻居,在加入队列便于BFS时可能会出现循环的情况,因此在检查一个人前应该先检查这个人是不是已经检查过了(用一个数组实现)。队列的数据表达形式和列表很像?

7.先用散列表(dict)实现图,然后用队列实现BFS。BFS的运行时间为O (V + E ),其中V 为(存入队列的)顶点(vertice)数,E为(图的)边数。

8.如果任务A依赖于任务B,在列表中任务A就必须在任务B后面,这被称为拓扑排序。树是一种特殊的图,没有往后指的边。

9.面临类似于寻找最短路径的问题时,可尝试使用图来建立模型,再使用广度优先搜索(BFS)来解决问题。

第七章——狄克斯特拉算法

1.狄克斯特拉算法(Dijkstra’s algorithm),解决最快路径的问题,包括四个步骤:(1) 找出最便宜的节点,即可在最短时间内前往的节点,并确保没有到该节点的更便宜的路径。(2) 对于该节点的邻居,检查是否有前往它们的更短路径,如果有,就更新其开销。 (3) 重复这个过程,直到对图中的每个节点都这样做了。 (4) 计算最终路径。最短路径指的并不一定是物理距离,也可能是让某种度量指标最小。

2.带权重的图称为加权图(weighted graph),不带权重的图称为非加权图(unweighted graph)。要计算非加权图中的最短路径,可使用广度优先搜索(BFS)。要计算加权图中的最短路径,可使用狄克斯特拉算法。在无向图中,两个节点彼此指向对方,其实就是环,每条边都是一个环,狄克斯特拉算法只适用于有向无环图 (directed acyclic graph,DAG),并且如果有负权边,也不能使用狄克斯特拉算法,在包含负权边的图中,要找出最短路径,可使用另一种算法:贝尔曼-福德算法(Bellman-Ford algorithm)。

第八章——贪心算法

1.教室调度问题:使用贪心算法解决,每步都采取局部最优解,最终得到的就是全局最优解,在这个问题中是每次都选择结束最早的课。

2.背包问题:有时候只需找到一个能够大致解决问题的算法,此时贪婪算法正好可派上用场,因为它们实现起来很容易,得到的结果又与正确结果相当接近。

3.集合覆盖问题:运行时间本来是O(2n),但用贪心算法之后时间变为O(n2)?python中创建集合用set函数,类似于列表,但集合中的值只能出现一次,使用集合来表示一切可以简化工作。并集符号:|,交集符号:&,差集符号:-。

4.出现错误:AttributeError: ‘NoneType’ object has no attribute ‘items’。很有可能粗心大意在生成变量的函数最后忘记返回这个变量了。

5.快速排序不是贪心算法(是递归的),广度优先搜索和狄克斯特拉算法是贪心算法。

6.旅行商问题是np完全问题(O(n!))(教室调度问题?、背包问题、集合覆盖问题都是np完全问题,背包可用动态规划求最优解,教室调度、集合覆盖可用贪心算法求最接近最优解的近似解),可近似求解,如贪心算法解决。狄克斯特拉算法解决的最短路径是从a点到b点求最短路径,但如果要找出经由指定几个点的最短路径(出发点和到达点没有明确,可以自由组合的)成了旅行商问题(np完全问题)。

7.没办法判断问题是不是NP完全问题,但还是有一些蛛丝马迹可循的(见书P255):

(1)元素较少时算法的运行速度非常快,但随着元素数量的增加,速度会变得非常慢。

(2)涉及“所有组合”的问题通常是NP完全问题。

(3)不能将问题分成小问题,必须考虑各种可能的情况,这可能是NP完全问题。

(4)如果问题涉及序列(如旅行商问题中的城市序列)且难以解决,它可能就是NP完全问题。

(5)如果问题涉及集合(如广播台集合)且难以解决,它可能就是NP完全问题。

(6)如果问题可转换为集合覆盖问题或旅行商问题,那它肯定是NP完全问题。

8.贪心算法寻找局部最优解,并企图以这种方式获得全局最优解,实际一般求得近似解,运行时间是O(n^2)。对于NP完全问题(运行时间是O(n!),还没有找到快速解决方案,最佳的做法是使用近似算法,贪心算法易于实现、运行速度快,是不错的近似算法。

第九章——动态规划

1,动态规划将问题分成小问题,并先着手解决这些小问题,然后再解决大问题。

2.使用动态规划解决背包问题时,要么考虑拿走整件商品,要么考虑不拿,而没法判断该不该拿走商品的一部分。但贪心算法可以解决,首先,尽可能多地拿价值最高的商品,如果拿光了,再尽可能多地拿价值次高的商品,依次类推。

3.动态规划功能强大,它能够解决子问题并使用这些答案来解决大问题,但仅当每个子问题都是离散的,即不依赖于其他子问题时,动态规划才管用。并且动态规划可在给定约束条件下找到最优解。

4.但最优解(价值最大)也有可能导致背包没有装满。

5.例题9.2:

1磅 2磅 3磅 4磅 5磅 6磅
水(3磅,价值10)w 0 0 10 w 10 w 10 w 10 w
书(1磅,价值3)b 3 b 3 b 10 w 13 wb 13 wb 13 wb
食物(2磅,价值9)f 3 b 9 f 12 fb 13 wb 19 wf 22 wfb
夹克(2磅,价值5)j 3 b 9 f 12 fb 14 fj 19 wf 22 wfb
相机(1磅,价值6)c 6 c 9 f/cb 15 fc 18 fbc 20 fjc 25 wfc

携带水、食物、相机价值最大

6.最长公共子串、最长公共序列(动态规划解决)需要再学习。

7.动态规划的公式并没有可用于所有情况的。

8.例题9.3:计算blue和clues最长公共子串

c l u e s
b 0 0 0 0 0
l 0 1 0 0 0
u 0 0 2 0 0
e 0 0 0 3 0

第十章——K最近邻算法

1.KNN做两项基本工作——分类和回归:分类就是对当前样本编组;回归就是对于最近的几个邻居的结果做平均,从而预测当前样本的结果(如一个数字)。相似度比较时用到欧式距离或余弦相似度公式(夹角余弦),余弦相似度不计算两个矢量的距离,而比较它们的角度。

2.机器学习例子:创建推荐系统,OCR(光学字符识别)(一般而言,OCR算法提取线段、点和曲线等特征),创建垃圾邮件过滤器,但用机器学习预测股票市场不可能实现。

3.能否挑选合适的特征事关KNN算法的成败。

第十一章——其他十种算法

1.树:数据结构二叉查找(排序)树(binary search tree),对于其中的每个节点,左子节点的值都比它小,而右子节点的值都比 它大,在二叉查找树中查找节点时,平均运行时间为O (log n ),但在最糟的情况下所需时间为O (n);而在有序数组中二分(折半)查找时,即便是在最糟情况下所需的时间也只有O(log n);二叉查找树的插入和删除操作的速度比数组的O(n)要快得多(O(log n));二叉查找树不能随机访问(和数组一样可以指定访问第几个元素),在二叉查找树处于平衡状态时,平均访问时间也为O (log n )。

B树(平衡二叉树,又称AVL树),B+树的区别参考链接:https://www.cnblogs.com/lianzhilei/p/11250589.html(待学习)

AVL(高度平衡的二叉搜索树,又称B树)与红黑树(R-B树,红黑树也是二叉查找树,统计性能要好于平衡二叉树)的区别和联系,在C++ STL中,很多部分(目前包括set,multiset, map, multimap)都应用了红黑树的变体,参考连接:https://www.cnblogs.com/rednodel/p/9259134.html(待学习)

2.反向索引:用一个散列表,将单词映射到包含它的页面。这种数据结构被称为反向索引(inverted index),常用于创建搜索引擎。

3.傅立叶变换:一个网站Better Explained致力于以通俗易懂的语言阐释数学:https://betterexplained.com/。

傅立叶用于处理数字信号,可压缩音乐、JPG也是一种压缩格式、用于地震预测和DNA分析等。

4.并行算法:对于算法速度的提升并非线性的。

5.MapReduce:一种流行的分布式算法,可通过开源工具Apache Hadoop来使用它。分布式算法非常适合用于在短时间内完成海量工作,其中的MapReduce基于两个简单的理念:映射(map)函数和归并(reduce)函数。映射是将一个数组转换为另一个数组,归并函数理念是将很多项归并为一项(将一个数组转换为一个元素)。MapReduce使用这两个简单概念在多台计算机上执行数据查询(数据集很大)。

6.布隆过滤器和HyperLogLog:

布隆过滤器是一种概率型数据结构,它提供的答案有可能不对,但很可能是正确的,如为google搜集未搜索过的网页时:可能出现错报的情况,即Google可能指出“这个网站已搜集”,但实际上并没有搜集;不可能出现漏报的情况,即如果布隆过滤器说“这个网站未搜集”,就肯定未搜集。

HyperLogLog近似地计算集合中不同的元素数,与布隆过滤器一样,它不能给出准确的答案,但也八九不离十,而占用的内存空间却少得多。面临海量数据且只要求答案八九不离十时,可考虑使用概率型算法。

7.SHA算法:secure hash algorithm(安全散列算法),给定一个字符串,SHA返回其散列值(一个较短的字符串)。用于创建散列表的散列函数根据字符串生成数组索引,而SHA根据字符串生成另一个字符串。

用处:(1)通过比较两个或以上文件的SHA散列值,判断是否是同一个文件;(2)检查密码,如:Gmail只存储密码的SHA散列值,不存储密码,避免黑客攻击。SHA实际上是一系列算法:SHA-0、SHA-1、SHA-2和SHA-3。

SHA算法是局部不敏感的,即:假设对一个字符串计算了其散列值,如果修改其中一个字符,在计算其散列值,结果完全不同。

8.局部敏感的散列算法:可使用Simhash,如果对字符串做细微的修改,Simhash生成的散列值也只存在细微的差别。这样可以通过比较散列值来判断两个字符串的相似程度。

用处:(1)Google使用Simhash来判断网页是否已搜集。(2)老师可以使用Simhash来判断学生的论文是否是从网上抄的。(3)Scribd允许用户上传文档或图书,以便与人分享,但不希望用户上传有版权的内容,这个网站可使用Simhash来检查上传的内容是否与小说《哈利·波特》类似,如果类似,就自动拒绝。

需要检查两项内容的相似程度时,Simhash很有用。

9.Diffie-Hellman密钥交换:RSA算法也可以了解。

10.线性规划:用于在给定约束条件下最大限度地改善指定的指标,所有的图算法都可使用线性规划来实现,线性规划是一个宽泛得多的框架,图问题只是其中的一个子集。可了解Simplex算法。

你可能感兴趣的:(算法,图论,数据结构)