算法回顾

第一章:算法简介

二分查找:


log10100相当于问“将多少个10相乘 的结果为100,答案是两个:10 × 10 = 100。因此,log10100 = 2。

算法效率:

总结:

  1. 二分查找的速度比简单查找快得多。
  2. O(log n)比O(n)快。
  3. 需要搜索的元素越多,前者比后者就快得越多。
  4. 算法运行时间并不以秒为单位。
  5. 算法运行时间是从其增速的角度度量的。
  6. 算法运行时间用大O表示法表示。

第二章:选择排序

数组与链表

  数组 链表中的元素可存储在内存的任何地方。链表的每个元素都存储了下一个元素的地址,从而使一系列随机的内存地址串在一起

链表存在类似的问题。在需要读取链表的最后一个元素时,你不能直接读取,因为你不知道 它所处的地址,必须先访问元素#1,从中获取元素#2的地址,再访问元素#2并从中获取元素#3 的地址,以此类推,直到访问最后一个元素。需要同时读取所有元素时,链表的效率很高:你读 取第一个元素,根据其中的地址再读取第二个元素,以此类推。但如果你需要跳跃,链表的效率 真的很低。 数组与此不同:你知道其中每个元素的地址。例如,假设有一个数组,它包含五个元素,起 始地址为00,那么元素#5的地址是多少呢?
选择排序

需要检查的元素数越来越少 随着排序的进行,每次需要检查的元素数在逐渐减少,最后一次需要检查的元素都只有一 个。既然如此,运行时间怎么还是O(n2)呢?这个问题问得好,这与大O表示法中的常数相关。

总结:

  1. 计算机内存犹如一大堆抽屉。
  2. 需要存储多个元素时,可使用数组或链表。
  3. 数组的元素都在一起。
  4. 链表的元素是分开的,其中每个元素都存储了下一个元素的地址。数组 的读取速度很快。 链表的插入和删除速度很快。
  5. 在同一个数组中,所有元素的类型都必须相同(都为int、double 等)。

第三章:递归 递归 如果使用循环,程序的性能可能更高;如果使用递归,程序可能 更容易理解。如何选择要看什么对你来说更重要

编写递归函数时,必须告诉它何时停止递归。正因为如此,每个递归函数都有两部分:基线 条件(base case)和递归条件(recursive case)。递归条件指的是函数调用自己,而基线条件则 指的是函数不再调用自己,从而避免形成无限循环。 我们来给函数countdown添加基线条件。 def countdown(i):
print i
if i <= 0:
return else:
countdown(i-1) 现在,这个函数将像预期的那样运行,如下所示。 栈 压入 (插入)和弹出(删除并读取)。

总结:

  1. 递归指的是调用自己的函数。
  2. 每个递归函数都有两个条件:基线条件和递归条件。
  3. 栈有两种操作:压入和弹出。
  4. 所有函数调用都进入调用栈。
  5. 调用栈可能很长,这将占用大量的内存。

第四章:快速排序

分而治之

(divide and conquer,D&C)——一种著名的递归式问题解决方法 D&C的工作原理: (1) 找出简单的基线条件; (2) 确定如何缩小问题的规模,使其符合基线条件。 D&C并非可用于解决问题的算法,而是一种解决问题的思路。

快速排序

小结

  1. D&C将问题逐步分解。
  2. 使用D&C处理列表时,基线条件很可能是空数组或只包含一个元 素的数组。
  3. 实现快速排序时,请随机地选择用作基准值的元素。
  4. 快速排序的平均运行时间为O(n log n)。
  5. 大O表示法中的常量有时候事关重大,这就是快速排序比合并排序快的原因所在。
  6. 比较简单查找和二分查找时,常量几乎无关紧要,因为列表很长时,O(log n)的速度比O(n) 快得多。

第五章:散列表

散列函数


散列,数组,链表

小结

这里总结一下,散列表适合用于:

  1. 模拟映射关系;
  2. 防止重复;
  3. 缓存/记住数据,以免服务器再通过处理来生成它们。
  4. 你可以结合散列函数和数组来创建散列表。
  5. 冲突很糟糕,你应使用可以最大限度减少冲突的散列函数。
  6. 散列表的查找、插入和删除速度都非常快。
  7. 散列表适合用于模拟映射关系。
  8. 一旦填装因子超过0.7,就该调整散列表的长度。
  9. 散列表可用于缓存数据(例如,在Web服务器上)。
  10. 散列表非常适合用于防止重复。

第六章:广度优先搜索

广度优先算法

广度优先搜索让你能够找出两样东西之间的最短距离,不过最短距离的含义有很多!

  1. 使用广 度优先搜索可以:
  2. 编写国际跳棋AI,计算最少走多少步就可获胜;
  3. 编写拼写检查器,计算最少编辑多少个地方就可将错拼的单词改成正确 的单词,如将 READED改为READER需要编辑一个地方;

根据你的人际关系网络找到关系最近的医生。

广度优先搜索的运行时间为 O(人数 + 边数),这通常写作O(V + E),其中V为顶点(vertice)数,E为边数。

队列

队列是一种先进先出(First In First Out,FIFO)的数据结构,而栈是一种后进先出(Last In First Out,LIFO)的数据结构。

小结

  1. 广度优先搜索指出是否有从A到B的路径。
  2. 如果有,广度优先搜索将找出最短路径。
  3. 面临类似于寻找最短路径的问题时,可尝试使用图来建立模型,再使用广度优先搜索来 解决问题。
  4. 有向图中的边为箭头,箭头的方向指定了关系的方向,例如,rama→adit表示rama欠adit钱。
  5. 无向图中的边不带箭头,其中的关系是双向的,例如,ross - rachel表示“ross与rachel约 会,而rachel也与ross约会”。
  6. 你需要按加入顺序检查搜索列表中的人,否则找到的就不是最短路径,因此搜索列表必 须是队列。
  7. 对于检查过的人,务必不要再去检查,否则可能导致无限循环。

第七章:迪克斯特拉算法

狄克斯特拉算法

广度优先搜索来查找两点之间的最短路径,那时“最短路径”的意思是 段数最少。 在狄克斯特拉算法中,你给每段都分配了一个数字或权重,因此狄克斯特拉算法找出 的是总权重最小的路径

狄克斯特拉算法包含4个步骤。

  1. 找出最便宜的节点,即可在最短时间内前往的节点。
  2. 对于该节点的邻居,检查是否有前往它们的更短路径,如果有,就更新 其开销。
  3. 重复这个过程,直到对图中的每个节点都这样做了。
  4. 计算最终路径。
    在无向图中,每条边都是一个环。狄克斯特拉算法只适用于有向无环图(directed acyclic graph,DAG)。

小结

  1. 广度优先搜索用于在非加权图中查找最短路径。
  2. 狄克斯特拉算法用于在加权图中查找最短路径。
  3. 仅当权重为正时狄克斯特拉算法才管用。
  4. 如果图中包含负权边,请使用贝尔曼福德算法。

第八章:贪婪算法

教室调度问题

贪婪算法很简单:每步都采取最优的做法。在这个示例中,你每次都选择结束最早的 课。用专业术语说,就是你每步都选择局部最优解,最终得到的就是全局最优解

具体做法如下。 (1) 选出结束最早的课,它就是要在这间教室上的第一堂课。 (2) 接下来,必须选择第一堂课结束后才开始的课。同样,你选择结束最早的课,这将是要 在这间教室上的第二堂课。

背包问题

假设你是个贪婪的小偷,背着可装35磅(1磅≈0.45千克)重东西的 背包,在商场伺机盗窃各种可装入背包的商品。

集合覆盖问题

假设你办了个广播节目,要让全美50个州的听众都收听得到。为 此,你需要决定在哪些广播台播出。在每个广播台播出都需要支付费 用,因此你力图在尽可能少的广播台播出

如何找出覆盖全美50个州的最小广播台集合呢?听起来很容易,但其实非常难。具体方法如下。 (1)列出每个可能的广播台集合,这被称为幂集(power set)。可能的子集有2n个。

近似算法

贪婪算法可化解危机!使用下面的贪婪算法可得到非常接近的解。

  1. 选出这样一个广播台,即它覆盖了最多的未覆盖州。即便这个广播台覆盖了一些已覆盖 的州,也没有关系。
  2. 重复第一步,直到覆盖了所有的州。 这是一种近似算法(approximation algorithm)。在获得精确解需要的时间太长时,可使用近 似算法。

判断近似算法优劣的标准如下:

  1. 速度有多快;
  2. 得到的近似解与最优解的接近程度。
  3. 贪婪算法是不错的选择,它们不仅简单,而且通常运行速度很快。在这个例子中,贪婪算法 的运行时间为O(n2),其中n为广播台数量

旅行商问题详解

旅行商问题和集合覆盖问题有一些共同之处:你需要计算所有的解,并从中选出最小/最短 的那个。这两个问题都属于NP完全问题

近似求解

对旅行商问题来说,什么样的近似算法不错呢?能找到较短路径的算法就算不错。在继续 往下阅读前,看看你能设计出这样的算法吗? 我会采取这样的做法:随便选择出发城市,然后每次选择要去的下一个城市时,都选择还 没去的最近的城市。假设旅行商从马林出发。 总旅程为71英里。这条路径可能不是最短的,但也相当短了

小结

  1. 贪婪算法寻找局部最优解,企图以这种方式获得全局最优解。
  2. 对于NP完全问题,还没有找到快速解决方案。
  3. 面临NP完全问题时,最佳的做法是使用近似算法。
  4. 贪婪算法易于实现、运行速度快,是不错的近似算法。

第九章:动态规划

动态规划

多维因素下的最优解
对于背包问题,你先解决小背包(子背包)问题,再逐步解决原来的问题。

可以偷商品的一部分吗?
答案是没法处理。使用动态规划时,要么考虑拿走整件商品,要么考虑不拿,而没法判断该 不该拿走商品的一部分。
但使用贪婪算法可轻松地处理这种情况!首先,尽可能多地拿价值最高的商品;如果拿光了, 再尽可能多地拿价值次高的商品,以此类推。

旅游行程最优化

没办法建模。动态规划功能强大,它能够解决子问题并使用这些答案来解决大问题。但仅当 每个子问题都是离散的,即不依赖于其他子问题时,动态规划才管用。这意味着使用动态规划算 法解决不了去巴黎玩的问题。

小结

  1. 需要在给定约束条件下优化某种指标时,动态规划很有用。
  2. 问题可分解为离散子问题时,可使用动态规划来解决。
  3. 每种动态规划解决方案都涉及网格。
  4. 单元格中的值通常就是你要优化的值。
  5. 每个单元格都是一个子问题,因此你需要考虑如何将问题分解为子问题。
  6. 没有放之四海皆准的计算动态规划解决方案的公式。

第十章: K最近邻算法

回归


基本工作——分类和回归:

  1. 分类就是编组;
  2. 回归就是预测结果(如一个数字)。

OCR

OCR指的是光学字符识别(optical character recognition)

小结

  1. KNN用于分类和回归,需要考虑最近的邻居。
  2. 分类就是编组。
  3. 回归就是预测结果(如数字)。
  4. 特征抽取意味着将物品(如水果或用户)转换为一系列可比较的数字。
  5. 能否挑选合适的特征事关KNN算法的成败。

第十一章:余下十种算法

二叉查找树(binary search tree)


注意,这棵树是向右倾斜的,因此性能不佳。也有一些处于平衡状态的特殊二叉查找树, 如红黑树。

反向索引

傅里叶变换

SHA算法

比较文件

检查密码

局部敏感的散列算法


Diffie-Hellman密钥交换

线性规划

转载于:https://my.oschina.net/sunmin/blog/3024621

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值