clllll  

算法简介

算法要么有速度,要么解决有趣的问题。

二分法

当有序的时候。就要想到二分法。

  • 范围缩小到只包含一个元素
def binary_serach(arr, target):
	left = 0
	right = len(arr) - 1
	while left <= right:  # 缩减到只包含一个元素
		mid = (left + right) / 2 
		if arr[mid] == item:
			return mid 
		elif arr[mid] > item:
			right = mid - 1 
		else:
			left = mid + 1 
	return None 

图算法编写跟踪用户的AI系统。

K最近邻算法编写推荐系统

NP完全问题。

Non-deterministic Polynomial的问题,即多项式复杂程度的非确定性问题。
用穷举法得到答案,一个个检验下去才能得到答案

对数

对数运算是幂运算的逆运算

10^2= 100 log 10 100 = 2

2^3 = 8 log2 8 = 3

大O运行时间

O(log n):对数时间。 二分查找
O(n): 线性时间
O(n * log n) :快速排序
O(n^2): 选择排序
O(n !) :旅行商问题

数组和链表 选择排序

数组:内存连续
链表:内存不需要连续。

递归

递归:代码简单,不容易理解。

要慢慢收敛,分俩个条件:

  • 基线条件:函数啥时候停止
  • 递归条件:函数啥时候调自己

快速排序

分而治之。 divide and conquer --递归式解决问题

1: 找出简单的基线条件
2: 如何缩小问题的规模,使其符合基线条件。

农场主分土地。均匀的分成方块,最大可分成的方块大小是多少。

拿当前较小的边为边长分割。剩余土地的继续。直到正好分割完毕。

def quicksork(arr):
	# 基线条件
	if len(arr) < 2:
		return arr 
	pivot = arr[0]
	less = [ i for i in arr[1:] if i <= pivot]
	greater = [i for i in arr[1:] if i > pivot]	
	return quicksort(less) + [pivot] + quicksort(greater)	

这种 更好理解。比起在原数组上向右扩大区域。就是浪费空间。

散列表

查找的速度为O(1)

散列函数

能把输入映射成一个数字。 同样的输入映射的数字一定一样。

散列冲突

输入是无限的。输出是有限的。可能32位或者64位,再大点128位。
好的散列函数生成的是均匀的。如果冲突。当前位置就存储成链表。

填装因子

当前散列表的元素 / 位置总数
填装因子大于0.7。就该调整了。

广度优先搜索

breadth-firsh-search . BFS

BFS可以找出俩样东西之间最短的距离。

  • 计算最少走多少步获胜
  • 拼写检查器,最少编辑多少个地方就可将错拼的单词改成正确的单词
  • 人际关系找最近的医生

使用图来建立模型,通过BFS来解决问题。

图由节点和边组成的。

第一类问题:从A有到B的路径吗
第二类问题:从A到B最短的路径。

实现图

python就是暴力,用字典。

g = {} 
g["you"] = ["alice", "bob", "claire"]
g["bob"] = ["anuj", "peggy"]
g["alice"] = ["peggy"]
g["claire"] = ["thom", "jonny"]
g["anuj"] = []
g["peggy"] = [] 
g["thom"] = [] 
g["jonny"] = [] 

实现算法

from collections import deque

s_q = deque() 
s_q += g["you"]
s_d = [] 
s_d.append("you")

while s_q:
	current_person = s_q.popleft()
	if current_person in s_d:
		continue 
	if current_persion[-1] == 'm':
		print(f"{current_person} is a mango seller!")
		return True 
	else:
		s_q += g[current_person]
return False 

迪克斯特拉算法

加权图
有最短路劲,但不一定是最快的。还有最快路劲。边有权。

1、 找出最便宜的节点。
2、 更新该节点的邻居的开销,如果有更快的,则更新邻居节点的开销。
3、 重复
只适用于有向无环图 directed acyclic graph .DAG ,不能有负权。

算法实现

g: 图
costs: 每个节点的开销。
parents: 最小开销的父节点


# 构造图模型
g = {} 
g["start"] = {}
g["start"]["a"] = 6
g["start"]["b"] = 2

g["a"] = {}
g["a"]["fin"] = 1 

g["b"] = {} 
g["b"]["a"] = 3 
g["b"]["fin"] = 5 

g["fin"] = {} 


infinity = float("inf")

processed = [] # 保存已经锁定的 

costs = {} 
costs["start"] = 0 
for item in g["start"].keys():
	costs[item] = g["start"][item] 

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 

lowest_node = find_lowest_cost_node(costs):

while node:
	current_cost = costs[lowest_node]
	for n in g[lowest_node].keys():
		new_cost = current_cost + g[lowest_node][n]
		if costs[n] > new_cost:
			costs[n] = new_cost 
			parents[n] = lowest_node 
	processed.append(lowest_node)
	lowest_node = find_lowest_cost_node(costs)

贪婪算法

如何处理不可能完成的任务
识别NP完全问题
近似算法得到NP完全问题的近似解
贪婪策略

教室调度问题

如何在这间教室上更多的课。

1)选出结束最早的课。
2)选出第一堂课结束后才开始的课。

贪婪算法:每步都选择局部最优解,最终得到就是全局最优解。

背包问题

包里只能装35磅的东西。如何能使包里装的东西最贵。
贪婪:直接装最贵的,依次装下一个能装下最贵的。
显然这个不是。证明贪婪算法是错误的,只需要举反例。
这个需要动态规划解决。

集合覆盖问题

广播节目需要50个州全部听到。决定哪些广播台播出。尽可能少的广播台。
每个广播台都有覆盖的州。
如何找出覆盖全美50个州最小广播台集合。

1)列出每个可能的广播台集合。 幂集 power set . 2^n 个。
2)在这些集合中选出覆盖全美50个州的最小集合。

没有任何算法可以快速的解决这个问题。

近似算法

1) 选出一个广播台。覆盖了最多的未覆盖的州,已覆盖了也没关系。
2) 重复第一步。直到覆盖了所有的州。

NP完全问题

为解决集合覆盖问题,必须计算每个可能的集合。
阶乘问题。需要计算所有的解。
如果能够判断出要解决的问题属于NP完全问题,就不需要寻找完美的解决方案。使用近似算法即可。

贪婪算法就是不错的近似算法。

动态规划

  • 解决棘手问题,将问题分成小问题。并先着手解决小问题。

背包问题

先解决小背包的问题。在逐步解决原来的问题。

每个动态规划算法都从一个网格开始。从左到右。从上到下。
行为商品,列为包的容量

网格最初是空的。
值为在背包容量为当前列的大小的时候。可以装当前行及之前行的东西。最大的价值是多少。

填当前格的时候。要不要装当前行的和装当前行俩种选择。

当然还要判断能否装的下当前商品。

cell[i][j] = max(cell[i-1][j]), 当前商品价值 + cell[i-1][j - 当前商品重量])
子问题必须是离散的。 不依赖其他子问题。动态规划才管用。

最长公共子串

如果用户拼写错误了。猜测他原本要输入的是什么单词。
HISH : FISH or VISTA
fosh : fish or fort

绘制网格

三个问题
1:单元格的值是什么
2:如何将这个问题划分为子问题
3:网格的坐标轴是什么

hish和fish最长公共子串是ish.

if word_a[i] == word_b[j]:
	# 俩个字母相同
	cell[i][j] = cell[i-1][j-1] + 1 
else:
	# 俩个字母不同:
	cell[i][j] = 0 

fosh和fish的最长公共子序列3(fsh)

if word_a[i] == word_b[j]:
	# 如果俩个字母相同,那就+1 
	cell[i][j] = cell[i-1][j-1] + 1 
else:
	# 俩个不同,取 左和上 较大的一个
	cell[i][j] = max(cell[i-1][j], cell[i][j-1])

K最近邻算法

  • 使用K最近邻算法创建分类系统
  • 特征抽取
  • 回归,预测数值。

橙子还是柚子

看它的邻居,最近的三个邻居,如果橙子比柚子多,那么很可能是橙子。
k-nearest neighbours , KNN. 进行分类。

创建推荐系统

电影推荐系统
将用户转换为一组数子的方式。
然后计算用户之间的空间距离:毕达哥斯拉公式
还有使用余弦相似度的 cosine similarity

回归

不仅仅推荐电影,还要预测给电影大多少分。
分类是编组,回归就是预测结果,一个数字。
计算K近邻的平均值。 这就是回归。

挑选合适的特征

考虑各种各样的因素。别单调,

OCR

光学字符识别: optical character recognition
1): 浏览大量的数字图像,将这些数字的特征提取出来
2): 遇到新图像,提取该图像的特征,再找出它最近的邻居都是谁。

OCR提取线段、点和曲线等特征

创建垃圾邮件过滤器

使用的是--朴素贝叶斯分类器 Naive Bayes classifier

先要有数据进行训练。很多邮件已经被标注为 垃圾邮件和非垃圾邮件
收到主题为“collect your million dollars now”, 这是垃圾邮件吗? 研究这个句子中的每个单词,看看它在垃圾邮件中出现的概率

机器学习的前提都是训练机器,喂数据。

Next Do What ?

二叉查找树 binary search tree 左子节点的值都比它小。右子节点都比它大。

反向索引

三个网页A: hi, there B:hi, adit , C: there we go

我们根据这些内容创建一个散列表。值为包含指定单词的页面。
hi: A,B
there: A,C
用户搜索 hi, 就可以返回A,B
一个散列表,将单词映射到包含它的页面,这种数据结构被称为 反向索引 inverted index

傅里叶变换

给它一杯沙,能告诉你其中包含哪些成分
给它一首歌曲,能够将其中的各种频率分离出来

并行算法

海量数据处理相关。 排序算法的速度大概是n * log n。为提高算法的速度。要在多个内核中并行地执行。

  • 并行性管理开销: 如何分配到多个内核,如何合并结果
  • 负载均衡: 让内核能够发挥自己最大的性能

MapReduce

分布式算法,算法在多台计算机上运行

映射 map 和 归并 reduce

布隆过滤器

判断一个东西是否已经存在。不需要100% 的正确性。数据量大。

布隆过滤器是一种概率型数据结构。 提供的答案有可能不对,但是很有可能是对的。
不会出现漏报的情况。如果没有,那么肯定没有。

SHA算法

散列函的结果是均匀分布的。局部不敏感。接收一个字符串,返回一个索引号。

可以用来比较文件。检查密码。

有时候又希望散列函数局部敏感。字符串只有细微的差别,那么生成的散列值也只存在细微的差别。比如检查小说是否盗版。

Diffie-Hellman密钥交换

如何对消息加密,只有收件人能看懂呢?

使用俩个密钥:公钥和私钥 。
使用公钥加密消息,只有对应的私钥才能解密。 私钥只有自己知道。所以,只有自己才能解密消息。

线性规划

在给定约束的条件下最大限度地改善指定的指标。

所有的图算法都是使用线性规划来实现的。。。

读后感

这本书写的感觉很实在。比java 好多了。
也提供了很多其他思路,比如快速排序,当然左神的在当前数组右扩左扩肯定是最优的,但是这里的实现就很 容易懂。。
动态规划和贪婪算法和左神讲的差不多哈哈。
人生苦短,要用python啊。

刻画了 动态规划,绘制表格,从小问题入手。大问题就自然而然解决了。

python里的图使用字典就可以构造。 当然java也可以。
只是字典这种模型就很容易理解,结构很清晰。

过年太影响计划了。。
关于算法,首推这本书。
挺讨厌刷题的啊啊啊啊啊啊啊啊。
3.1日晚。

posted on 2023-03-01 22:45  llcl  阅读(159)  评论(0编辑  收藏  举报