《算法图解》读书笔记 -- 针对入门

算法图解 读书笔记
前三章分别是 二分查找 数组和链表 递归
二分查找的核心思路:利用双指针,每次比较完成之后,重新定位指针的位置。
选择排序:数组和链表
需要储存多项数据时,有两种基本方式:数组和链表。
链表的元素可以储存在内存的任何地方,每个元素都储存了下一个元素的地址,使用链表的时候 根本不需要移动元素 当想要插入元素时 只要有足够内存。但是在若想要读取最后一个元素 需要依次读取前面的元素。
数组:数组的储存空间都是连续的
所以是:数组的读取是O1,插入是On, 删除是On,链表的读取是On,插入是O1.删除是O1,因为访问的模式有两种:随机访问和顺序访问,显然数组是随机访问而链表是顺序访问。
第二种算法:选择排序(第一种是二分查找)
选择排序的核心:每次都遍历剩下的列表,Pop出最大的那个放到一个新的列表中。时间复杂度为O(n2)
第三章 递归
递归和循环是解决问题的两种方式
这两种方式各有可取之处 但是在一些情况下,递归显然是更好的方法。
由于递归函数调用自己 因此很容易出错(也不好想!)
可能会导致的错误有:无限循环。所以我们必须要注意的一个问题就是:递归函数包含两个条件:基线条件和递归条件。基线条件是:结束语句。
栈和递归:
Def fact(x)
If x==1:
Return 1
Else:
Return x*fact(x-1)
请注意,每一次x都被重新赋值,就是一层一层的叠栈,一直到最底层,然后一层一层的弹出,每一层只是写与上一层的函数关系,知道最底层才做一些实际实例的问题。
第四章
下面讲 快速排序
这是用divide and conquer的一个很好的实例,同样,咋快速排序中也用到了递归
比如说 你需要写一个关于数组元素加和结果的函数:(例如2,4,6)
第一步
找出基线条件:找最简单的 如果数组不包含任何元素或者只包含一个元素,那就是他本身了。但是这也太抽象了吧。

现在看一下快速排序:快速排序的核心思想是选取一个Povit值,我们只需要找出比基准值大的值和比基准值小的值然后放在右边或者左边
快速排序的基线条件为空数组或者只包含一个元素,在这些情况下 只需要原样返回数组即可。
代码:
Def quicksort(array):
If len(array)<2:
Return array-----基线条件
Else:
Pivot = array[0]-------递归条件
Less == [I for I in array[1:] IF I<=PIVOT]
GREATER = [I for I in array[1:] IF I>PIVOT]
Return quicksort(less)+[pivot] +quicksort(great)#返回值采用了递归语句。
我们要讲第三种排序:merge and sort(合并排序)利用了divide and conquer语句
第五章 散列表(哈希表)
也是基本数据结构的一种。我们之前说过简单查找与二分查找,其时间复杂度分别是On和Ologn,但是散列表的时间复杂度却只有O1. 哈希表尤其要注意的是他的散列函数的选取,溢出的应对措施。已经哈希表的用途(用做缓存-采用URL映射)
溢出的应对措施?在冲突发生的时候在那个位置储存一个链表。即使如此,我们仍然像尽可能地找到较好的哈希函数,下面介绍一种:安全散列算法(SHA)这种常用于密码的计算,这种算法是单向的,可以由原始值推断出散列值,但是无法由散列值倒推回去。

还要注意,虽然散列表的最糟情况是On但是其平均情况是O1
第六章 广度优先搜索
图(node+edge) 的一个重要性质就是 他是节点之间的 任意链接 (相比于树和链表的整洁)
广度优先搜索(BFS),可以让你找出两样东西之间的最短距离(广义,因为最短距离有很多解释)比如:
根据人际网络计算关系最近的医生 编写拼写检查器。
从本质上来说,就像二分查找一样,广度优先搜索是一种用于图的查找算法。广度优先搜索可以解决以下两种问题:
1 从节点A出发,有前往节点B的路径吗?
2 从A出发,前往节点B的哪条路径最短。
就是说 不但要找到 还要最短的。这就要求,先找到 先添加选用 使用 队列 来实现这一想法,其余代码见 图解算法.py
很明显 广度优先搜索的运行时间为O(v+n).

下面讲 另外一种排序 拓扑排序。树 是一种特殊的 图,就是说一点概念。
第七章 迪克斯特拉算法(只适用于有向无环图)
这是一种算法 能够让你找出加权图中的最短路径 这种算法与广度优先搜索算法同级。
此算法包含四个步骤:
1 找出最便宜的节点 即可以在最短时间内前往的节点。
2 对于该节点的邻居 检查是否有前往他们的更短路径 如果有 就更新其开销(意思是对于同一个节点,我们如果有更快的方式到达他们,就将之前的路径更新为更快的路径)
3 重复这个过程 知道对途中的每个节点都这样做了
4 计算最终路径
还有一个例外 当图中包含负权边时 采用 贝尔曼-福德算法

第八章 贪婪算法
贪婪算法主要用于处理:没有快速算法 的问题,这种问题也叫NP完全问题。那么如何识别属于这种问题的问题呢?
贪婪问题解决的核心思想是:每一步都寻找局部最优解,最后就有可能找到总体最优解.
NP问题的典型实例就是:旅行商人问题 和 集合覆盖问题(如果你忘记是什么的话,请去算法图解126页寻找。他们的共同之处,也是NP问题的一个重要特征:你需要计算所有的解 并从其中选出最小或者最短的那个。下面是常见的NP问题特征,复合此特征的就优先考虑贪婪算法。
1 元素较少是算法运行速度较快,但是随着数量的增加,速度变得非常慢(On!)
2 设计需要看所有组合的问题
3 不能将问题分解成更小的子问题 需要考虑到各种情况
4 如果问题涉及序列
5 如果问题设计到集合
第九章 动态规划 是一种解决棘手问题地方法
其核心是:将问题分解成子问题—但是如何解决这个问题呢?
如上一章所说,贪婪算法是解决NP问题的叫好方法,他能快速找出近似解,但大多数时候可能不是最优解 那么我们要用动态规划解决这一问题。
下面以小偷背包问题为例:
如何利用有限的空间偷走最大的价值。
分析思路:
先解决小背包(子背包)问题,先看包只有一磅的最高价值,再看二磅(取之前一磅能承载的最大价值+剩下的一磅能承载的最大价值 与 两磅能承载的最大价值 取最大值 在这个过程中 把所有的东西依次添加?),再看三磅(0+3 或者1+2 或者2+1 或者3+0) 再往下看四磅。。。
但是我们想问题的过程应该是翻过来?但是为什么呢?
另外一个动态规划问题: 旅游行程最优化(page147)但是最后却声称动态规划解决不了这些问题,由此引出当每个子问题都是离散的 即 不依赖于其他子问题时,动态规划才管用?难道之前的背包问题不是子问题相互依赖吗?那么什么叫相互依赖呢?
动态规划方法带来的启示:
可以帮你在给定约束条件下找到最优解(比如背包容量一定 偷到价值最高的商品)
当问题可以分解为彼此独立且离散的子问题 考虑动态规划 但是具体设计动态规划解决方案会很困难。以下是几种建议:
每种动态规划解决方案都涉及网格,网格的xy坐标的选取。
比如下例:寻找两个字符串的最大公共字符串(用于字典网站猜用户的输入以及纠错)
其他应用实例:DNA最长公共序列判断 指出两个文件的差异 盗版抄袭检查 word的断字功能以确保行长一致。
最后一条公理:没有通用的计算动态规划方案的公式。
第十章 K最近邻算法(k-nearest neighbours)
应用实例:Netflix 推荐系统(计算口味相似度之间的距离,看看与哪些人最相近)现在 更进一步 我们不仅要想用户推荐电影 还要预测他会打多少分,为此 要先找离他最近的k个人。
利用k最近邻可以做两项基本工作:分类和回归 分类就是编组 回归就是预测结果。
之前在计算两种情况(两个用户)的距离时 使用的都是距离公式,但是在实际生活中会有更加合适的公式,比如 余弦相似度(cosine similarity),如果要应用的话一定要研究这个。
综上 考虑的方面越多 就会越全面 预测出的结果也会更加准确,但是人力毕竟是有限的。这就凸显的计算机的强大,机器学习营运而生。
机器学习简介:
OCR:光学字符识别 (利用KNN,浏览大量数字图像 提取该图像特征 再找处其最近的邻居是谁)同样的理念也可以应用于语音识别和人脸识别。
垃圾邮件过滤器:(利用 navie bayes classifier)
预测股票市场。
怎样尽可能多的收集有用的数据 并将其转化为特征值就尤为重要,这是人们需要做的工作。大数据分析就交给计算机去做。
第十一章 其他算法简介:
树:由于在数组中查找时 最快的方式是二分查找(有序数组)。采用了二叉查找树(binary search tree),其一个重要特征就是 左子节点值都比他小 而右子节点值都比他大。然而二叉查找树还是与有序数组存在相当的区别:
有序数组的查找为(Ologn),插入和删除都是O(n),而二叉查找树都是O(logn).
反向索引:(蕴含搜索引擎的搜索原理):一个散列表 将单词映射到他的页面,这种数据结构称为 反向索引。(inverted index)
傅里叶变换:其能将文件成分中的各种元素的频率分析出来,应用于MP3压缩,JPG,地震预测 DNA分析,各种音乐识别软件。
以下对多线程处理和海量数据有关:
并行算法:有一种很流行的并行算法叫MAP reduce,可以通过流行的开源工具apache hadoop来使用,他的效用体现在能短时间内处理大量工作 为什么呢》因为他能实现多线程 用单线程和双线程,当数据量较小时感觉不到差别 但是1天和两天之比将会差异巨大。
MapReduce基于两个简单的理念:映射函数和归并函数,下面分别来看:
映射函数:见code
归并函数:(见code)
布隆过滤器和hyperloglog:(这种算法统称为概率型算法)
布隆过滤器:散列表虽然速度快 但是同样意味着占用许多空间,有时候这种占用空间是十分不经济的,因此我们采用布隆过滤器进行优化。使用散列表的结果一定可靠 但是使用布隆过滤器,可能出现报错的情况(指出某网站已在数据库中,但实际上没有),但是不会出现(指出某网站不在数据库中 但是实际上存在的情况),这样只会一步一步完善数据库。
Hyperloglog:是一种类似于布隆过滤器的算法 他可以近似的计算集合中不同的元素数,虽然不能给出准确答案 但是结果也十分近似。
下面介绍 安全散列算法(SHA)
这种算法核心是一种散列函数 将接受给定的字符串 返回一个独一无二的索引号。这种算法的重要特征之一就是 局部不敏感 也就是说 只要有一点点原始字符串的不同 其索引号就会完全不一样。
此外另一种加密算法 Diffie hellman算法 这种算法对消息进行加密 使得只有收件人才能看懂 这种算法解决了两个问题:发件收件双方并不需要知道加密算法 要破解加密消息十分困难。
他使用两个密钥 公钥和私钥 发件人用公钥进行加密 用私钥进行解密,具体研究 请搜索相关算法。
线性规划算法:用于在给定约束条件下最大限度改善指定的指标 需要注意的是 所有的图算法都可以用线性规划来实现 线性规划是一个宽泛得多的框架 而图问题 只是其中的一个子集

你可能感兴趣的:(Reading,Notes)