文章目录

  • 1. 大O表示法
    • 1. 旅行商前往n个城市,确保旅程最短。求可能的排序:n!种可能方案
    • 2. 仅当列表是有序的时候,二分查找才管用
  • 2. 选择排序
    • 1. 数组 & 链表
  • 3.递归
    • 1. 递归
    • 2. 栈
  • 4. 快速排序
  • 5. 散列表
  • 6. 广度优先搜索
  • 7. 狄克斯特拉算法(计算加权图的最短路径)
  • 8. 贪婪算法
  • 9. 动态规划
  • 10. K最近邻算法
  • 11. 扩展

1. 大O表示法

  • 算法的运行时间用大O表示法表示
  • 大O运行时间转换为操作数
  • 算法的速度指的并非时间,而是操作数的增速(随着输入的增加,其大O运行时间将以什么样的速度增加)
快到慢函数 函数
O(1) 常量时间,哈希
O(log2(n)) 对数时间,二分查找
O(n) 线性时间,简单查找
O(nlog2(n)) 快速排序
O(n2) 选择排序(冒泡)
O(n!) 旅行商问题
  • 说明:

1. 旅行商前往n个城市,确保旅程最短。求可能的排序:n!种可能方案

2. 仅当列表是有序的时候,二分查找才管用

# 简单查找
def search(target_list,item):for i in target_list:if i == item:return ireturn None# 二分查找
def binary_search(tlist,item):low = 0high = len(tlist)-1while low <= high:mid = int((low + high)/2)if item < tlist[mid]:high = mid-1elif item >tlist[mid]:low = mid+1else:return (mid,tlist[mid])return None

2. 选择排序

1. 数组 & 链表

  • 数组: 内存中连续存储,随意查询元素,随机查询快(知道索引),增删改慢(因为有顺序,有预设内存空间,中间插入或者超出预留内存,就会重新构建)

  • 链表: 内存中分散,每一个元素记录下一个元素位置,随机查询慢(只能从第一个往后推),要全部查询的情况下也不慢,增删改快(分散存储只要更改上一个元素的记录)

# 选择排序(冒泡排序)
# 先把数组中最小值找到,然后把该最小值添加到一个新数组中def findsmallest(arr):smallest_index = 0smallest_num = arr[0]for i in range(1, len(arr)):if smallest_num > arr[i]:smallest_index = ismallest_num = arr[i]return smallest_indexdef selectsort(arr):""":param arr::return: new arr for sorted"""new_arr = []for i in range(len(arr)):smallest_index = findsmallest(arr)new_arr.append(arr.pop(smallest_index))return new_arr

3.递归

1. 递归

  • 递归指的是调用自己的函数
  • 每个递归函数都有两个条件:基线条件和递归条件
  • 尾递归 (将结果也放入函数参数,内存里面调用栈只有一个当前运行的函数进程)

2. 栈

  • 栈是一种简单的后进先出数据结构,栈有两种操作:压入(插入)和弹出(删除并读取)

  • 所有函数调用都进入调用栈

  • 调用栈可能很长,这将占用大量的内存

  • 调用栈: 每当调用函数时,计算机都像这样将函数调用涉及的所有变量的值存储到内存中。调用另一个函数时,当前函数暂停并处于未完成状态。该函数的所有变量的值都还在内存中。这个栈用于存储多个函数的变量,被称为调用栈。

# 递归 阶乘f(n) = n!def fact(x): if x == 1:return 1else:return x * fact(x-1)  #注意这里跟尾递归不同# 尾递归
def factorial(x,result):  if x == 1:return resultelse:return factorial(x-1,x*result)if __name__ == '__main__':print(fact(5)) #5*4*3*2*1 = 120print(factorial(5,1)) #120

4. 快速排序

  • 快速排序使用分而治之的策略
分而治之D&G(divide and cpnquer)工作原理:
1. 找出基线条件,这个条件必须尽可能的简单
2. 不断将问题分解(或者说缩小规模),直到符合基线条件

涉及数组的递归函数时,基线条件通常是数组为空或只包含一个元素。陷入困境时,请检查基线条件是不是这样的

# D&C和递归应用举例# 列表元素值求和
def sum(list):if not list:return 0return list[0] + sum(list[1:])# 编写一个递归函数来计算列表包含的元素数
def count(list):if not list:return 0return 1 + count(list[1:])# 找出列表中最大数字
def max(list):if len(list) == 2:return list[0] if list[0] > list[1] else list[1]sub_max = max(list[1:])return list[0] if list[0] > sub_max else sub_maxprint(sum([1, 3, 6, 2, 9, 0]))
print(count([1, 3, 6, 2, 9, 0]))
print(max([1, 3, 6, 2, 9, 0]))
# 两种快速排序,平均运行时间为 O(n * log n)# 基准值为第一个元素
def quicksort(sort_list):if len(sort_list) < 2:return sort_listelse:base_num = sort_list[0]less = [i for i in sort_list[1:] if i <= base_num]greater = [i for i in sort_list[1:] if i > base_num]return quicksort(less) + [base_num] + quicksort(greater)  # []直接列表化 和 list()将可迭代对象列表化# 基准值为最中间元素
def quicksort2(sort_list):if len(sort_list) < 2:return sort_listelse:mid_index = len(sort_list) // 2less = [i for i in sort_list[:mid_index] if i <= sort_list[mid_index]] + \[i for i in sort_list[mid_index + 1:] if i <= sort_list[mid_index]]greater = [i for i in sort_list[:mid_index] if i > sort_list[mid_index]] + \[i for i in sort_list[mid_index + 1:] if i > sort_list[mid_index]]return quicksort2(less) + [sort_list[mid_index]] + quicksort2(greater)print(quicksort([10, 5, 2, 3, 6]))
print(quicksort2([10, 5, 2, 3, 6]))
  • 合并排序,或者叫归并排序
  1. 合并排序也是建立在归并操作上的一种有效的排序算法。也是采用分治法的一个非常典型的应用

  2. 合并排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列

  3. 归并排序的时间复杂度任何情况下都是 O(n*log n),但并不如快排应用广泛,因为归并排序的合并函数,在合并两个有序数组为一个有序数组时,需要借助额外的存储空间,也就是说它不是原地排序算法

# 冒泡排序时间复杂度O(n^2)def simpleSort(array):for i in range(len(array)-1):for j in range(i,len(array)):if array[i] > array[j]:temp = array[i]array[i] = array[j]array[j] = tempreturn arrayprint(simpleSort([9,8,6,7,4,5,3,11,2])) #[2, 3, 4, 5, 6, 7, 8, 9, 11]
# 归并排序时间复杂度是O(nlogn) ,最坏情况也是O(nlogn)
def mergeSort(array):if len(array) < 2:return arrayelse:mid = int(len(array)/2)left = mergeSort(array[:mid])right = mergeSort(array[mid:])return merge(left, right)def merge(left, right): #并两个已排序好的列表,产生一个新的已排序好的列表result = []  # 新的已排序好的列表i = 0  # 下标j = 0# 对两个列表中的元素 两两对比# 将最小的元素,放到result中,并对当前列表下标加1while i < len(left) and j < len(right):if left[i] <= right[j]:result.append(left[i])i += 1else:result.append(right[j])j += 1# 此时left或者right其中一个已经添加完毕,剩下的就全部加到result后面即可      result += left[i:] result += right[j:]return resultarray = [9,5,3,0,6,2,7,1,4,8]
result = mergeSort(array)
print('排序后:',result) #排序后: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

5. 散列表

  • 散列函数

  • 散列函数是这样的函数,既无论你给它什么数据,它都还你一个数字。即散列函数"将输入映射到数字"

  • 散列表应用

1. 快速查找
2. 文件安全性传输交验
3. 可以防止重复 (一旦发现重复,该哈希函数就不安全了。也就是说被破译了)
4. 缓存/ 记住数据,以免服务器再通过处理来生成它们
  • 散列表
  • 散列表更复杂一些,它使用散列函数来确定元素的存储位置。。散列表也使用数组来存储数据,因此其获取元素的速度与数组一样快
小结
1. 散列表时一种功能强大的数据结构,其操作速度快,能以不同的方式建立数据模型。
2. 可以结合散列函数和数组来创建散列表。
3. 冲突很糟糕,应该使用可以最大限度减少冲突的散列函数。
4. 散列表的查找,插入和删除速度都非常快。
5. 散列表适合用于模拟映射关系。
6. 一旦装填因子超过0.7,就该调整散列表的长度.
7. 散列表可用于缓存数据。
8. 散列表非常适用于防止重复。

6. 广度优先搜索

  • 广度优先搜索采用双端队列

  • 处理过程中,将所有有关的节点都添加到处理队列中

  • 非加权图(无向图)中查找最短路径

  • 从你的朋友关系网中,找出一个芒果销售商。(假设芒果销售商名字是以m结尾)

from collections import deque#需编写函数person_is_seller,判断一个人是不是芒果销售商,如下所示。
def person_is_seller(name):return name[-1] == 'm' #这个函数检查人的姓名是否以m结尾:如果是,他就是芒果销售商。。def bfs(graph,name):search_queue = deque()search_queue += graph[name]#graph["you"]是一个数组,其中包含你的所有邻居,如["alice", "bob","claire"]。这些邻居都将加入到搜索队列中。searched =[]while search_queue:person = search_queue.popleft()if not person in searched:if person_is_seller(person):print(person + " is a mango seller!")return Trueelse:search_queue += graph[person]searched.append(person)return Falseif __name__=='__main__':graph = {}graph["you"] = ["alice", "bob", "claire"]graph["bob"] = ["anuj", "peggy"]graph["alice"] = ["peggy"]graph["claire"] = ["thom", "jonny"  ]graph["anuj"] = []graph["peggy"] = [] graph["thom"] = []graph["jonny"] = []print(graph)
'''
{'you': ['alice', 'bob', 'claire'],
'bob': ['anuj', 'peggy'],
'alice': ['peggy'],
'claire': ['thom', 'jonny'],
'anuj': [],
'peggy': [],
'thom': [],
'jonny': []}
'''bfs(graph,"you")  #thom is a mango seller!
  • 小结
  1. 广度优先搜索指出是否有从A到B的路径。
  2. 如果有,广度优先搜索将找出最短路径。
  3. 面临类似于寻找最短路径的问题时,可尝试使用图来建立模型,再使用广度优先搜索来解决问题。
  4. 有向图中的边为箭头,箭头的方向指定了关系的方向,例如,rama→adit表示rama欠adit钱。
  5. 无向图中的边不带箭头,其中的关系是双向的,例如,ross - rachel表示“ross与rachel约会,而rachel也与ross约会”。
  6. 队列是先进先出(FIFO)的。
  7. 栈是后进先出(LIFO)的。
  8. 你需要按加入顺序检查搜索列表中的人,否则找到的就不是最短路径,因此搜索列表必须是队列。
  9. 对于检查过的人,务必不要再去检查,否则可能导致无限循环。

7. 狄克斯特拉算法(计算加权图的最短路径)

  • 迪克斯特拉的关键4个步骤:
  1. 找出最便宜的节点,即可在最短时间内前往的节点
  2. 对于该节点的邻居,检查是否有前往它们的更短路径,如果有,就更新其开销
  3. 重复这个过程,直到对图中的每个节点都这样做了。
  4. 计算最终路径
# 将节点的所有邻居和和前往邻居的开销都存储在一个散列表
# 每个节点都有开销。开销指的是从起点前往该节点需要多长时间

graph = {}
graph["Start"] = {}
graph["Start"]["A"] = 6
graph["Start"]["B"] = 2
graph["A"] = {}
graph["A"]["End"] = 4
graph["B"] = {}
graph["B"]["C"] = 1
graph["B"]["End"] = 7
graph["C"] = {}
graph["C"]["A"] = 4
graph["C"]["End"] = 5infinity = float("inf")
costs = {}
costs["A"] = 6
costs["B"] = 2
costs["C"] = infinity
costs["End"] = infinityparents = {}
parents["A"] = "Start"
parents["B"] = "Start"
parents["C"] = None
parents["End"] = Nonedef findLowestCostNode(costs, processed):lowest_cost = infinitylowest_cost_node = Nonefor node in costs:cost = costs[node]if cost < lowest_cost and node not in processed:lowest_cost = costlowest_cost_node = nodereturn lowest_cost_nodedef Dijkstra():processed = []node = findLowestCostNode(costs, processed)while node is not None and node != "End":cost = costs[node]neighbors = graph[node]for n in neighbors.keys():new_cost = cost + neighbors[n]if new_cost < costs[n]:costs[n] = new_costparents[n] = nodeprocessed.append(node)node = findLowestCostNode(costs, processed)Dijkstra()
print(costs)
print(parents)
# 小结
# 1. 计算非加权图中的最短路径,使用广度优先搜索。
# 2. 计算加权图中的最短路径,使用狄克斯特拉算法。即只适用于有向无环图(DAG)
# 3. 最短路径指的并不一定是物理距离,也可能是让某种度量指标最小
# 4. 如果图中包含负权边,请使用贝尔曼-福德算法

8. 贪婪算法

  • 贪婪算法寻找局部最优解,企图以这种方式获得全局最优解,易于实现、运行速度快,是不错的近似算(一种 NP 完全问题的近似解)
  • 广度优先搜索与迪克斯特拉算法都算贪婪算法
# 判断NP方法的一些条件
1. 元素较少时算法的运行速度非常快,但随着元素数量的增加,速度会变得非常慢
2. 涉及"所有组合"的问题通常是NP完全问题
3. 不能将问题分成小问题,必须考虑各种可能的情况。这可能是NP完全问题
4. 如果问题涉及序列(如旅行商问题中的城市)且难以解决,它可能就是NP完全问题
5. 如果问题涉及集合(如广播台集合)且难以解决,它可能就是NP完全问题
6. 如果问题可转换为集合覆盖问题或旅行商问题,那它肯定是NP完全问题

9. 动态规划

  • 动态规划:将问题分成小问题,并先着手解决这些小问题,都可以画网格解决
  1. 小偷背包问题

def bag(goods,size):cell = [[0 for col in range(size)] for row in range(len(goods))] package_size= [i+1 for i in range(size)] for j in range(size):if(goods[0][1]<=package_size[j]):cell[0][j] = goods[0][0]for i in range(1,len(goods)):for j in range(size):if (package_size[j]-goods[i][1]>0) and (goods[i][0] + cell[i-1][package_size[j]-1-goods[i][1]]) > cell[i-1][j]:cell[i][j] = goods[i][0] + cell[i-1][package_size[j]-goods[i][1]-1]elif (package_size[j]-goods[i][1]==0) and (goods[i][0] > cell[i-1][j]): cell[i][j] = goods[i][0]else:cell[i][j] = cell[i-1][j]print(cell)  #[[1500, 1500, 1500, 1500], [1500, 1500, 1500, 3000], [1500, 1500, 2000, 3500]]return cell[len(goods) - 1][size - 1]if __name__ == '__main__':goods = [[1500,1],[3000,4],[2000,3]]print(bag(goods,4)) #3500
  1. 最长公共子串(fish和hish)

# 最长公共子串
if word_a[i] == word_b[j]:cell[i][j] = cell[i-1][j-1] + 1
else:cell[i][j] = 0
  1. 最长公共子序列(fish和fosh)

# 最长公共子序列
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])

10. K最近邻算法

  • KNN算法真的是很有用,堪称你进入神奇的机器学习领域的领路人!
  • 使用KNN 来做两项基本工作—— 分类和回归,需要考虑最近的邻居
  • 要计算两点的距离(相似程度),可使用毕达哥拉斯公式:

  •  分类就是编组  回归就是预测结果(如一个数字)–凭着得出的相似程度计算估值

  • 选择邻居个数一般为sqrt(n)个数,n为总量

  • 特征抽取意味着将物品(如水果或用户)转换为一系列可比较的数字

  • 除了距离公式,实际上更常用余弦相似度

  • 机器学习的例子
1. 水果分类
2. 电影推荐系统
3. OCR指的是光学字符识别(optical character recognition)(1)浏览大量的数字图像,将这些数字的特征提取出来。 --训练(2)遇到新图像时,你提取该图像的特征,再找出它最近的邻居都是谁!(3)这与判断水果是橙子还是柚子时一样。OCR算法提取线段、点和曲线等特征
4. 垃圾邮件过滤器(1)使用一种简单算法——朴素贝叶斯分类器 (Naive Bayes classifier )(2)朴素贝叶斯分类器能计算出邮件为垃圾邮件的概率,其应用领域与KNN 相似

11. 扩展

  1. 二叉树,B树(数据库常用它来存储数据),红黑树,堆,伸展树

# 二叉树
- 对于其中的每个节点,左子节点的值都比它小,而右子节点的值都比它大
  1. 反向索引
# 反向索引(inverted index)
- 一个散列表,将单词映射到包含它的页面。反向索引常用于创建搜索引擎。
  1. 傅里叶变换
# 傅里叶变换
- 傅里叶变换非常适合用于处理信号
- 傅里叶变换能够将其中的各种频率分离出来
- 将音频文件分解为音符。傅里叶变换能够准确地指出各个音符对整个歌曲的贡献,让你能够将不重要的音符删除
- 压缩音乐如MP3,图片JPG,地震预测和DNA分析
  1. 并行算法
# 并行算法
- 要改善性能和可扩展性
- 速度并不是线性的,会受到并行性管理开销和负载均衡的影响
  1. MapReduce
# MapReduce
-  MapReduce基于两个简单的理念:映射(map)函数和归并(reduce)函数
-  映射是将一个数组转换为另一个数组
-  归并是将一个数组转换为一个元素arr1 = [1, 2, 3, 4, 5]
arr2 = map(download_page, arr1)     # [2, 4, 6, 8, 10]
reduce(lambda x,y: x+y, arr1)       # 15
  1. 布隆过滤器和 HyperLogLog
# 概率型算法
- 概率型数据结构,使用散列表时,答案绝对可靠,而使用布隆过滤器时,答案却是很可能是正确的
- 它不能给出准确的答案,但也八九不离十,而占用的内存空间却少得多
  1. SHA 算法
- 散列函数是安全散列算法(secure hash algorithm ,SHA )函数)
- 给定一个字符串,SHA返回其散列值,可用于比较文件/检查密码
  1. 局部敏感的散列算法
- 如:Simhash。(SHA算法局部不敏感)
- 需要检查两项内容的相似程度时,Simhash很有用
  1. Diffie-Hellman 密钥交换
- Diffie-Hellman使用两个密钥:公钥和私钥    --非对称加密
  1. 线性规划
- 线性规划使用Simplex算法,使结果最优化,约束条件是某些变量

读书笔记 --《算法图解》相关推荐

  1. 读书笔记 | 墨菲定律

    1. 有些事,你现在不做,永远也不会去做. 2. 能轻易实现的梦想都不叫梦想. 3.所有的事都会比你预计的时间长.(做事要有耐心,要经得起前期的枯燥.) 4. 当我们的才华还撑不起梦想时,更要耐下心来 ...

  2. 读书笔记 | 墨菲定律(一)

    1. 有些事,你现在不做,永远也不会去做. 2. 能轻易实现的梦想都不叫梦想. 3.所有的事都会比你预计的时间长.(做事要有耐心,要经得起前期的枯燥.) 4. 当我们的才华还撑不起梦想时,更要耐下心来 ...

  3. 洛克菲勒的38封信pdf下载_《洛克菲勒写给孩子的38封信》读书笔记

    <洛克菲勒写给孩子的38封信>读书笔记 洛克菲勒写给孩子的38封信 第1封信:起点不决定终点 人人生而平等,但这种平等是权利与法律意义上的平等,与经济和文化优势无关 第2封信:运气靠策划 ...

  4. 股神大家了解多少?深度剖析股神巴菲特

    股神巴菲特是金融界里的传奇,大家是否都对股神巴菲特感兴趣呢?大家对股神了解多少?小编最近在QR社区发现了<阿尔法狗与巴菲特>,里面记载了许多股神巴菲特的人生经历,今天小编简单说一说关于股神 ...

  5. 2014巴菲特股东大会及巴菲特创业分享

     沃伦·巴菲特,这位传奇人物.在美国,巴菲特被称为"先知".在中国,他更多的被喻为"股神",巴菲特在11岁时第一次购买股票以来,白手起家缔造了一个千亿规模的 ...

  6. 《成为沃伦·巴菲特》笔记与感想

    本文首发于微信公众帐号: 一界码农(The_hard_the_luckier) 无需授权即可转载: 甚至无需保留以上版权声明-- 沃伦·巴菲特传记的纪录片 http://www.bilibili.co ...

  7. 读书笔记002:托尼.巴赞之快速阅读

    读书笔记002:托尼.巴赞之快速阅读 托尼.巴赞是放射性思维与思维导图的提倡者.读完他的<快速阅读>之后,我们就可以可以快速提高阅读速度,保持并改善理解嗯嗯管理,通过增进了解眼睛和大脑功能 ...

  8. 读书笔记001:托尼.巴赞之开动大脑

    读书笔记001:托尼.巴赞之开动大脑 托尼.巴赞是放射性思维与思维导图的提倡者.读完他的<开动大脑>之后,我们就可以对我们的大脑有更多的了解:大脑可以进行比我们预期多得多的工作:我们可以最 ...

  9. 读书笔记003:托尼.巴赞之思维导图

    读书笔记003:托尼.巴赞之思维导图 托尼.巴赞的<思维导图>一书,详细的介绍了思维发展的新概念--放射性思维:如何利用思维导图实施你的放射性思维,实现你的创造性思维,从而给出一种深刻的智 ...

  10. 产品读书《滚雪球:巴菲特和他的财富人生》

    作者简介 艾丽斯.施罗德,曾经担任世界知名投行摩根士丹利的董事总经理,因为撰写研究报告与巴菲特相识.业务上的往来使得施罗德有更多的机会与巴菲特亲密接触,她不仅是巴菲特别的忘年交,她也是第一个向巴菲特建 ...

最新文章

  1. Oracle RAC环境下如何更新patch(Rolling Patch)
  2. LeetCode Ugly Number
  3. “正则表达式”应当称为“规则表达式”
  4. 8、MySQL注释:单行注释和多行注释
  5. python之环境变量(测试环境可配置)(亲测)
  6. linux终端使用python3,3 个 Python 命令行工具 | Linux 中国
  7. Jerry带您了解Restful ABAP Programming模型系列之二:Action和Validation的实现
  8. 浏览器兼容:改写window.showModalDialog
  9. 【实施自动化测试项目】的7大必备条件!那些我踩过的坑......
  10. 多元有序logistic回归_stata速学|logistic回归分析
  11. 什么是恶意软件?病毒,蠕虫,特洛伊木马等有害程序
  12. CSS选择器的权重计算
  13. php分组统计求和,数据需求统计常用shell命令---AWK分组求和,分组统计次数
  14. TwinCAT 3 基础——编程基础
  15. CDR插件开发之GMS插件001 - 什么是GMS插件
  16. padavan mysql密码_padavan固件
  17. VIRTUALBOX无法加载USB移动设备的解决方法
  18. window10运行不了1stopt_软件与win10不兼容怎么办?完美解决Win10与软件不兼容的问题...
  19. 35岁鹅厂员工失业后嚎啕大哭...年轻新鹅分享省钱秘诀,每月除了房租水电,其他吃喝玩乐基本白嫖公司......
  20. 请简述final、finalize和finally的区别

热门文章

  1. VM虚拟机7.0,下载——安装全过程。
  2. 个人python学习(10)
  3. 甲骨文与亚马逊的云业务之争
  4. 宿主机使用wifi时虚拟机如何连网
  5. 【已解决】Error: ENOENT: no such file or directory, open ‘F:\xxx\node_modules\echarts
  6. 运行于老虎证券开放api的一个小小策略
  7. 一个一站式流式处理云平台解决方案
  8. java下载微信支付账单_java微信支付,对账单下载
  9. 吉首大学第八届“新星杯”题解AEGIJK
  10. 组策略——软件限制策略(完全教程与规则示例)