算法图解学习笔记三
第九章 动态规划
9.1 背包问题
问题简介:假设你是一个小偷,背包只能装4kg东西,你可盗窃的商品有如下三件:音响 3000美元 4千克 笔记本电脑 2000美元 3千克 吉他 1500美元 1千克
1.简单算法:尝试各种可能的商品组合,并找出价值最高的组合。------>可行但速度慢
3件商品 8种组合 4件商品 16种组合 运行时间O(2^n)
在前一章学习了如何找到近似解,但不一定是最优解
2.如何找最优解--->动态规划
先解决子问题,再解决大问题
画网格图 计算每个单元格的公式=max(1.上一个单元格的值(c[i-1][j]),2.当前商品的价值+剩余空间的价值(c[i-1][j-当前商品的重量]))
9.2 背包问题FAQ
1.再增加一件商品将如何?
加一个iPhone 前面几行不需要重新计算 因为动态规划是一个逐步计算最大价值的过程
沿着一列往下走,最大价值不可能降低,因为每次迭代时你储存的是当前的最大价值,最大价值不可能比以前低!
2.行的排列顺序发生改变时结果将如何?
没有编号,各行排列顺序无关紧要
3.可以逐列填充网络
4.增加一件更小的商品将如何呢?
假设你可以偷一条项链 0.5kg 1000美元 需要考虑的粒度更细,必须调整网格
5.可以偷走商品的一部分吗?
假设在杂货店偷,只有豆子和大米与面条,可偷一部分--->动态规划没法处理这个问题,动态规划要么不拿,要么拿一整件
使用贪婪算法 --->尽可能多拿价值高的商品,如果拿光了,在尽可能多拿价值次高的商品。
6.旅游行程最优化---背包问题 约束条件为时间 画网格图
7.处理相互依赖的情况
假如你还想去巴黎玩,解决不了。。仅当每个子问题都是离散的,即不依赖于其他子问题时,动态规划才有用。
8.计算最终的解时会涉及两个以上的子背包吗?
动态规划最多只需合并两个子背包,即更根本不会涉及两个以上的子背包,不过这些子背包又可能包含子背包。
9.最优解可能导致背包没装满
9.3 最长公共子串
1.动态规划问题带来的启示:
(1).动态规划可在给定约束条件下找到最优解
(2).问题可分解为彼此独立且离散的子问题时可使用动态规划。但要设计出动态规划解决法案maybe很难
(3).每种动态规划解决方案都涉及网络
(4).单元格中的值通常是你要优化的值。
(5).每个单元格都是一个子问题 --->learn 如何将问题分解为子问题,有助\'于找到网格的坐标轴
ALEX输入了hish,那原来它要输入的是fish还是vista?
2.绘制网格 填充网格
怎么绘制? 单元格中的值是什么?如何将这个问题划分为子问题?网格的坐标轴是什么?
将某个指标最大化-------->找两个单词的最长公共子串 单元格中的值是我要优化的值
| H | I | S | H | |
| F | 0 | 0 | 0 | 0 |
| I | 0 | 1 | 0 | 0 |
| S | 0 | 0 | 2 | 0 |
| H | 0 | 0 | 0 | 3 |
使用什么公式呢?费曼算法(Feynman) 步骤:
(1)将问题写下来 (2)好好思考 (3)将答案写下来
如果两个字母不相同则为0,相同则为左上角邻居的值+1
伪代码:
if word_a[i]=word_b[j]:#两个字母相同 cell[i][j]=cell[i-1][j-1]+1 else: cell[i][j]=0
查找hish与vista的最长公共子串时,网格如下
| V | I | S | T | A | |
| H | 0 | 0 | 0 | 0 | 0 |
| I | 0 | 1 | 0 | 0 | 0 |
| S | 0 | 0 | 2 | 0 | 0 |
| H | 0 | 0 | 0 | 0 | 0 |
需要注意的是:这个问题的最终答案不在最后一个单元格中!
背包问题---->答案总在最后的单元格中 但对于最长公共子串问题---->答案为网格中最大的数字
9.4 最长公共子序列
如果Alex不小心输入了fosh,他原本想输入的是fish还是fort呢?
我们用最长的公共子串公式来比较他们.
| F | O | S | H | |
| F | 1 | 0 | 0 | 0 |
| O | 0 | 2 | 0 | 0 |
| R | 0 | 0 | 0 | 0 |
| T | 0 | 0 | 0 | 0 |
| F | O | S | H | |
| F | 1 | 0 | 0 | 0 |
| I | 0 | 0 | 0 | 0 |
| S | 0 | 0 | 1 | 0 |
| H | 0 | 0 | 0 | 2 |
最长公共子串长度一样,都包含两个字母,但fosh与fish更像。
解决方法: 比较最长公共子序列:两个单词中都有的序列包含的字母数。
| F | O | S | H | |
| F | 1 | 1 | 1 | 1 |
| O | 1 | 2 | 2 | 2 |
| R | 1 | 2 | 2 | 2 |
| T | 1 | 2 | 2 | 2 |
最长公共子序列=2
| F | O | S | H | |
| F | 1 | 1 | 1 | 1 |
| I | 1 | 1 | 1 | 1 |
| S | 1 | 1 | 2 | 2 |
| H | 1 | 1 | 2 | 3 |
最长公共子序列=3
填写单元格的公式:
1.如果两个字母不同,则选择上方或者左方邻居中较大的那个 2.如果相同,则为左上方单元值+1
伪代码如下:
if word_a[i]==word_b[j]: cell[i][j]=cell[i-1][j-1]+1 else: cell[i][j]=max(cell[i-1][j],cell[i][j-1])
9.4 动态规划的具体应用
1.最长公共序列确定DNA链的相似性
2.git diff等命令 -->指出两个文件的差异 by动态规划实现
3.编辑距离(levenshtein distance)指出两个字符的相似程度 也是通过动态规划实现的
编辑距离算法应用从拼写检查到用户上传的资料是否为盗版。。。
4.Micro word等具有断字功能的应用程序,他们用动态规划来确定在哪个地方断字以确保行长一样
*****没有放之四海皆准的计算动态规划解决方案的公式*****
第十章 K最近邻算法
关键字: k最近邻算法 分类系统 特征抽取 回归 应用于局限性
10.1 橙子还是柚子
图标 以颜色由橙色到红色为y轴 以个头从小到大为x轴 O代表橙子 G代表柚子
橙子集中在左下角 柚子集中在右上角
如何判断这个水果十橙子还是柚子?----->一种办是看邻居
看它最近的三个邻居
这三个邻居中橙子比柚子多--->该水果很可能是橙子
---->这个方法就是k最近邻(k-nearest neighbours,KNN)算法 简单但很有用
10.2 创建推荐系统
假设你是Netflix,要为用户创建一个推荐系统。本质上类似于水果问题
1.将所有用户放入一个图表中,这些用户在图表中的位置取决于其喜好,喜欢相似的用户距离较近。
2.如果你想向tlf推荐电影,可以找到五位离她最近的用户。
如何确定两位用户的相似程度?
10.2.1特征抽取
水果案例中抽取个头和颜色 量化画二维坐标图
计算两点间的距离使用毕达哥拉斯公式
distance=sqrt((x1-x2)^2+(y1-y2)^2)
推荐系统案例: 想办法将用户放入图表中---转化为一组数字
| pr | ju | mo | |
| 喜剧片 | 3 | 4 | 2 |
| 动作片 | 4 | 3 | 5 |
| 生活片 | 4 | 5 | 1 |
| 恐怖片 | 1 | 1 | 3 |
| 爱情片 | 4 | 5 | 1 |
求五维空间的距离即可 距离越小相似程度越高
pr与ju喜好更接近,则只要ju喜欢的电影都推荐给pr。反之亦然
如果你是Netflix用户,Netflix不断提醒你去评分,你评论的电影越多 Netflix更能判断出你与哪些用户相似
练习:1.yogi和pinky欣赏电影的品味一样,但yogi给喜欢的电影打5分,而pinky更加挑剔,只给特别好的电影打5分。但根据距离算法,他们并非邻居,如何将这种评分方式的差异考虑进来?
可使用归一化。你可计算每位用户的平均分,并据此来调整用户的评分。例如,pinky的平均评分为3,yogi为3.5,因此你稍微提高pinky的评分,使其平均评分为3.5,这样就能基于同样的标准比较他们的评分了。
2.假设Netflix制定了一组意见领袖,因此他们的评分比普通用户更重要,要如何修改推荐系统,使其更偏重于意见领袖的评分呢?
可在使用knn时给领袖的评分更大的权重,a,b于领袖c对一个电影的评价分别为3,4,5星,可不这样计算(3+4+5)/3/=4,而这样算(3+4+5+5+5)/5=4.4
10.2.2 回归
预测tlf给这部推荐的电影打多少分?先找出于她最近的5个邻居,也可选择2个,1000个。。。这是为啥叫K最近邻算法的原因
取他们的平均分即预测值--->回归
KNN做的两项基本的工作---->分类和回归
分类:编组 回归:预测结果
计算两个用户的距离可以使用距离公式,也可以用余弦相似度。 余弦相似度不计算两个矢量的距离,而比较他们的角度。(练习1)
10.2.3 挑选合适的特征
需考虑各种因素。。
10.3 机器学习简介
10.3.1 OCR---->光学字符识别
你拍摄印刷页面的照片,计算机将自动识别出其中的文字。
比如识别数字: 点 线段 曲线
(1)浏览大量的数字图像,提取其特征。 - ---training
(2)遇到新图像时,提取她的特征,再找出她最近的邻居都是谁。
10.3.2 创建垃圾邮件过滤器
使用的简单算法: 朴素贝叶斯分类器(Naive Bayes classifier)
10.3.3 预测股票市场:
使用机器学习来预测股票涨跌太难了! 变数太多
第十一章 如何进阶
11.1 树
当用户登录Facebook时,Facebook必须在一个庞大的数组中查找,核实是否包含指定的用户名。最快的查找的方式:二分查找
问题在于:每注册一个新的用户时,就要插入后重新排序。
引入二叉查找树(binary search tree) 直接插入到正确位置
在二叉查找树查找节点 平均运行时间O(log n) 最糟情况:O(n)
插入与删除速度均为O(log n) 缺点:不能随机访问
一些处于平衡状态的特殊二叉查找树:红黑树
B树这种特殊的二叉查找树用于数据库储存数据
还有堆,伸展树
11.2 反向索引 散列表:将单词映射到包含它的页面
创建搜索引擎
11.3 傅里叶变换 ---绝妙 优雅 应用广泛
经常用于处理信号
MP3的工作原理:先将音频文件分解为音符,傅里叶变换能准确地指出各个音符对整个歌曲的贡献,让你将不重要的音符删去.
jpg也是一种压缩格式
同时傅里叶变换可用于地震预测与dna分析
11.4 并行算法
下面三个主题都与可扩展性和海量数据处理相关。
笔记本与台式机都是多核处理器,为提高算法速度,可让它们能在多个内核中并行执行.
例子:最佳情况 排序算法速度O(nlog n)
但快速排序的并行版本所需时间为O(n)
并行算法涉及很难,速度的提升非线性的,原因如下:
1.并行性管理开销 合并与分配都需要时间
2.负载均衡 内核直接的效率不一样或者分配任务的难度不一样会导致存在内核空闲
11.5 MapReduce 分布式算法---特殊的并行算法(非常流行)
并行算法只需两个到四个内核时,完全可在笔记本上面运行,if需要上百个内核,可让算法在多台计算机上运行。
分布式算法可通过开源工具Apache Hadoop来使用它
11.5.1分布式算法为啥很有用?
当有一个包含数亿甚至万亿行的数据库表,需对其进行复杂的SQL查询。in this case,你不能使用MySQL,but你可以通过Hadoop来使用mapreduce!
分布式算法非常适合用于在短时间内完成海量工作,其中mapreduce基于两个简单的原理:映射函数(map)和归并(reduce)函数。
11.5.2映射函数
simple,接守一个数组,并对其每个元素执行同样的处理。
>>>arr1=[1,2,3,4,5] >>>arr2=map(lambda x: 2*x ,arr1) [2,4,6,8,10]
这个很快啊,啪的一下算完了。
if需要执行的操作需要更多的时间呢?看下面伪代码
>>>arr1= # A list of URLs >>>arr2=map(download_page,arr1) #在这个示例中你有一个URL清单,需要下载每一个URL指向的页面并且将其 #储存到数组arr2中 每个URL处理起来都可能需要几秒钟,如果有1000多个 #,可能需要几小时!
如果有100台计算机,而map能够自动将工作分配给这些计算机去完成,这样可同时下载100个页面
11.5.3 归并函数
将很多项归并为一项
>>>arr1=[1,2,3,4,5] >>>reduce(lambda x,y:x+y,arr1) 15
mapreduce使用这两个概念在多台计算机上面执行数据查询,数据集很大,包含数十亿行时,使用mapreduce只需几分钟就能查获结果,而传统数据库可能要耗费数小时。
11.6 布隆过滤器和HyperLogLog
散列表查找是否已收集,但Google需要建立数万亿个索引。。。
解决方法:使用布隆过滤器:概率型数据结构 占用空间小
散列表 答案一定是正确的 布隆过滤器 答案可能时正确的。
HyperLogLog:类似于布隆过滤器 近似计算集合中不同的元素数
11.7 SHA算法(secure hash algorithm)
散列表查找O(1),希望散列函数的结果时均匀分布的。
1.比较文件
给定一个字符串,SHA返回其散列值
"hello"-------->2cf24db.....
对于不同的字符串,sha生成的散列值都不同,且散列值很长,这里截短了
"algorithm"---->b1eb2ec....
"password"------->5e884889..
可用其来判断两个文件是否相同,在比较大型文件时很有用。如比较两个4gb文件,只需要比较其散列值。
2.检查密码
在不知道原始字符串的情况进行比较。假设Gmail受到攻击,攻击者窃取了所有的密码,你的密码并没有暴露,因为Google储存的并非密码,而是密码的SHA散列值!你输入密码时,Google计算其散列值,并于数据库中的散列值进行比较。
这种散列算法是单向的,你只能根据字符串计算出散列值,不能根据散列值推断出原始字符串。
SHA实际上是一系列算法:SHA-0,SHA-1,SHA-2和SHA-3,本书编写期间,0和1已被发现存在一些缺陷,建议使用2和3.
最安全的密码散列函数是bcrypt,当然也存在绝对的安全。
11.8 局部敏感的散列算法
SHA有个重要特征就是局部不敏感.
dog----->cd6357 dot--------->e392da
修改一个字符后散列值完全不同
局部敏感的散列函数可使用Simhash,如果你对字符串进行细微的修改,其散列值也存在细微的差别。可通过散列值来判断两个字符串的相似程度。
应用:
1.google用它来判断网页是否收集。
2.老师用simhash来判断学生论文是否从网上抄袭
3.Scribd允许用户上传文档或图书,但不希望用户上传有版权的内容!这个网站可使用Simhash来检查上传内容是否于小说。。类似,如果类似,自动拒绝。
11.9 Diffie-Hellman 密钥交换
传统的加密算法存在不少安全问题
Diffie-Hellman算法解决了这两个问题:
1.双方无需知道加密算法,不必会面协商要使用的加密算法
2.要破解加密的信息比登天还难。
使用两个密钥:公钥和私钥。
公钥是公开的可随便发布。有人要向你发布信息时,他使用公钥加密,加密后的信息只有使用私钥才能解密。只有你自己才能解密消息。
Diffie-Hellman算法及其替代者RSA被广泛使用!
11.10 线性规划 最酷的算法之一
1.用于给定约束条件下最大限度地改善指定的指标。 ----最优化
2.所有的图算法都可用线性规划实现,图问题只是其中的一个子集。心潮澎湃
3.线性规划使用Simplex算法,很复杂。
11.11 结语
知道了很多地方等待你去探索,最佳的学习方法是找到感兴趣的主题,然后一头扎进去。