算法图解(读书笔记)

*爱你&永不变心* 提交于 2020-03-05 15:15:17

第一章

二分查找

  • 输入:一个有序的元素列表
  • 过程:要查找的元素包含在列表中,二分查找返回其位置,否则返回NULL
  • 对于包含n个元素的列表,用二分查找最多需要log2nlog_{2}n步,简单查找最多需要nn
  • 算法实现:
def binary_search(list,item):
	low=0
	high=len(list)-1
	while low<=high:
		mid=(low+high)/2  #向下取整
		guess=list[mid]
		if guess=item:
			reutrn mid
		if guess>item:
			high=mid-1
		else:
			low=mid+1
	return None  #None 表示空,意味着没有找到指定元素
  • 运行时间为对数时间(O(lognlog n))
    • 最多需要猜测的次数与列表长度相同,这被称为线性时间(linear time)
    • O(1)代表常量时间

大O表示法

  • 大O表示法指出了算法运行时间的增速,指出了最糟情况下的运行时间
  • 常见的大O运行时间
    • O(logn)O(log n):对数时间,比线性时间快,例如二分查找
    • O(n)O(n):线性时间,例如简单查找
    • O(nlogn)O(n logn):例如快速排序
    • O(n2)O(n^2):例如选择排序
    • O(n!)O(n!):例如旅行商问题
  • 算法的速度指的并非时间,而是操作数的增速。
  • 谈论算法的速度时,我们说的是随着输入的增加,其运行时间将以什么样的速度增加。
  • 算法的运行时间用大O表示法表示。

第二章

需要存储多项数据时,有两种基本方式-数组和链表

  • 数组
    • 添加元素慢且麻烦,有时可能会浪费内存
    • 读取简单,地址连续
    • 访问方式
      • 顺序访问:从第一个元素开始逐个读取元素
      • 随机访问:
    • 同一个数组中,所有元素的类型必须相同(int或double)
  • 链表
    • 元素可存储在内存的任何地方
    • 链表的每个元素都存储下一个元素的地址,从而使一系列随机的内存地址串在一起。
    • 不需要移动元素,只要有足够内存空间,就能为链表分配内存
    • 只能顺序访问
  • 数组和链表比较
    • 数组:读取O(1) 插入O(n)删除O(n)
    • 链表:读取O(n) 插入O(1)删除O(1)(当能够立即访问要删除的元素时)

快速排序

  • 运行时间O(nlogn)O(n logn)
  • 算法示例:
def findSmallest(arr):  
	smallest=arr[0]
	smallest_index=0
	for i in range(1,len(arr)):
		if arr[i]<smallest:
			smallest=arr[i]
			smallest_index=i
	return smallest_index
def selectinSort(arr):
	newArr=[]
	for i in range(len(arr)):
		smallest=findSmallest(arr)#找出数组中最小的元素,降入新数组
		newArr.append(arr.pop(smallest))
	return newArr

第三章

递归

  • 调用自己的函数
  • 作用:让解决方案更清晰,并没有性能上的优势
  • 循环使程序的性能更高,递归使程序更容易理解
  • 为了避免死循环,编写递归函数,必须告诉它何时停止递归
  • 递归函数包含两个部分:
    • 基线条件:函数不再调用自己,避免死循环
    • 递归条件:函数调用自己

  • 后进先出
  • 两种操作:
    • 压入(插入)
    • 弹出(删除并读取)
  • 所有函数调用都进入调用栈
  • 调用栈可能很长,将占用大量的内存

第四章

分而治之(D&C)

  • 解决问题:
    • (1)找出基线条件,这种条件必须尽可能简单。
    • (2)不断将问题分解(或者说缩小规模),直到符合基线条件。

快速排序

  • 流程:
    • (1)选择基准值。
    • (2)将数组分成两个子数组:小于基准值的元素和大于基准值的元素。
    • (3)对这两个子数组进行快速排序。
  • 算法实现
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(greater)
	print quicksort([10,5,2,3])
  • 最慢运行时间 O(n2)O(n^2),平均运行时间 O(nlogn)O(nlogn)

第五章

散列表和散列函数

  • 散列表是无序的,将输入映射到数字

  • 散列函数总是将同样的输入映射到相同的索引。

  • 散列函数将不同的输入映射到不同的索引。但常常会有冲突

  • 散列函数知道数组有多大,只返回有效的索引。

  • Python提供的散列表实现为字典,你可使用函数dict来创建散列表。

book=dict() #或book={}
book["apple"]=3
  • 散列表由键和值组成,散列表将键映射到值
  • 应用:用于查找 例如DNS解析,将网址映射为IP地址
    用于防止重复;用于缓存数据
  • 处理冲突的简单办法:如果两个键映射到了同一个位置,就在这个位置存储一个链表。
    • 为了避免冲突,需要较低的填装因子,良好的散列函数
      • 填装因子:散列表包含元素数/位置总数。填装因子越低,发生冲突可能性越小,性能越高。散列表适合用于模拟映射关系
      • 良好的散列函数让数组中的值呈均匀分布
  • 性能:查找,插入,删除的平均情况是O(1),最糟情况是O(n)
    在这里插入图片描述

第六章 广度优先搜索

广度优先搜索

解决最短路径问题的算法被称为广度优先搜索

  • 广度优先搜索是用于图的查找算法,帮助解决两类问题:
    • 有无路径
    • 路径最短
  • 图由节点和边组成
    • 有向图
    • 无向图:没有箭头,直接相连的节点互为邻居
  • 运行时间:O(V+E),V为顶点数,E为边数

队列

  • 先进先出(FIFO)
  • 操作:入队和出队

第七章 狄克斯特拉算法

  • 找出加权图中前往x的权重最小路径
  • 该算法只适用于有向无环图,对负权边不适用(可用贝尔曼-福德算法)
  • 于每条边都有关联数字的图,这些数字称为权重
  • 带权重的图称为加权图(weighted graph),不带权重的图称为非加权图(unweighted graph)
  • 无向图意味着两个节点彼此指向对方,其实就是
    注:python中表示无穷大infinity=float(“inf”)
def find_lowest_cost_node(costs):
	lowest_cost=float("inf")
	lowest_cost_node=None
	for node in costs:#遍历所有节点
		cost=costs[node]
		if cost<lowest_cost and node not in processed:
			lowest_cost=cost#视为开销最低节点
			lowest_cost_node=node
	return lowest_cost_node
node=find_lowest_cost_node(costs)#在未处理的节点中找出开销最小的节点
while node is not None:
	cost=costs[node]
	neighbors=graph[node]
	for n in neighbors.keys():
		new_cost=cost+neighbors[n]
		if costs[n] > new_cost:#如果经当前节点前往该邻居更近,
			costs[n]=new_cost#就更新该邻居的开销
			parents[n]=node#同时将该邻居的父节点设置为当前节点
	processed.append(node)#将当前节点标记为处理过
	node=find_lowest_cost_node(costs)
	

第八章 贪婪算法

  • 优点:简单易行,每步都采取最优的做法,得到的就是全局最优解
  • 常见问题:背包问题,集合覆盖问题
  • 贪婪算法寻找局部最优解,企图以这种方式获得全局最优解。

NP完全问题

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

  • 要判断问题是不是NP完全问题很难,易于解决的问题和NP完全问题的差别通常很小

    • 元素较少时算法的运行速度非常快,但随着元素数量的增加,速度会变得非常慢。涉及“所有组合”的问题通常是NP完全问题。
    • 不能将问题分成小问题,必须考虑各种可能的情况。这可能是NP完全问题。
    • 如果问题涉及序列(如旅行商问题中的城市序列)且难以解决,它可能就是NP完全问题。
    • 如果问题涉及集合(如广播台集合)且难以解决,它可能就是NP完全问题。
    • 如果问题可转换为集合覆盖问题或旅行商问题,那它肯定是NP完全问题。
  • NP完全问题,还没有找到快速解决方案。

  • 面临NP完全问题时,最佳的做法是使用近似算法。贪婪算法易于实现、运行速度快,是不错的近似算法。

近似算法

  • 优劣标准:
    • 速度有多快
    • 得到的近似解与最优解的接近程度

注:集合类似于列表,但不能包含重复的元素。可以做交并差集运算

第九章 动态规划

问题:背包问题

  • 动态规划先解决子问题,再逐步解决大问题

  • 动态规划可帮助你在给定约束条件下找到最优解。在背包问题中,你必须在背包容量给定的情况下,偷到价值最高的商品。

  • 在问题可分解为彼此独立且离散的子问题时,就可使用动态规划来解决。

  • 小建议:

    • 每种动态规划解决方案都涉及网格。
    • 元格中的值通常就是你要优化的值。在前面的背包问题中,单元格的值为商品的价值。
    • 每个单元格都是一个子问题,因此你应考虑如何将问题分成子问题,这有助于你找出网格的坐标轴。
  • 最长公共子串

  • 最长公共序列

  • 需要在给定约束条件下优化某种指标时,动态规划很有用。

  • 问题可分解为离散子问题时,可使用动态规划来解决。

  • 每种动态规划解决方案都涉及网格。单元格中的值通常就是你要优化的值。

  • 每个单元格都是一个子问题,因此你需要考虑如何将问题分解为子问题。

  • 没有放之四海皆准的计算动态规划解决方案的公式。

第十章 K最近邻法(KNN)

案例:创建推荐系统

  • 计算两点距离,可用毕达哥拉斯公式(x1x2)2+(y1y2)2\sqrt{(x_1-x_2)^2+(y_1-y_2)^2},距离指出了两组数字之间的相似程度
  • 还有计算方式是余弦相似度,比较的是角度
  • 利用KNN来做分类和回归,分类就是编组,回归就是预测结果
  • 特征抽取意味着将物品(如水果或用户)转换为一系列可比较的数字。能否挑选合适的特征事关KNN算法的成败。

案例:机器学习简介

  • OCR
    • OCR的第一步是查看大量的数字图像并提取特征,这被称为训练(training)。大多数机器学习算法都包含训练的步骤:要让计算机完成任务,必须先训练它
  • 创建垃圾邮件过滤器
    • 算法:朴素贝叶斯分类器

第十一章 接下来如何做

    • 二叉查找树
      • 特点:对于每个节点,左子节点值都比它小,右子节点的值都比它大
      • 在二叉查找树查找节点时,平均运行时间为 O(logn)O(logn),最糟为O(n)O(n)
      • 执行插入和删除操作速度快很多
    • 对数据库或高级数据结构感兴趣,请研究如下数据结构:B树,红黑树,堆,伸展树。
  • 反向索引

    • 常用于创建搜索引擎
  • 傅里叶变换

    • 适合处理信号,也可以用来压缩音乐,地震预测,DNA分析
  • 并行运算

  • MapReduce

    • 分布式运算提升速度和性能,适合短时间完成海量工作
    • 基于映射map函数和归并reduce函数
      • map函数:将一个数组转换为另一个数组
      • reduce函数:将很多项归并为一项
#map
arr1=[1,2,3,4,5]
arr2=map(lambda x:2*x,arr1) #[2,3,6,8,10]
#reduce
arr1=[1,2,3,4,5]
reduce(lambda x,y:x+y,arr1)#15

  • 布隆过滤器和HyperLogLog
  • SHA算法
    • 一种散列函数,安全散列算法(SHA),给定一个字符串,SHA返回其散列值(较短的字符串)
    • 可用SHA判断两个文件是否相同
    • 检查密码:存储的都是密码的SHA散列值,由于无法根据散列值推断出原始字符串
    • 希望散列函数是局部敏感的,可使用Simhash
  • Diffie-Hellman密钥交换
    • 使用两个密钥:公钥和私钥,加密的信息只有使用私钥才能解密
  • 线性规划
    • 线性规划用于在给定约束条件下最大限度地改善指定的指标
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!