二分查找:
def binary_search(list, item):
low = 0
high = len(list)-1
while low <= high:
mid = int((low + high)/2)
guess = list[mid]
if guess == item:
return mid
if guess < item:
low = mid+1
else:
high = mid-1
return None
my_list = [1,2,3,4,5,6,7,8]
print(binary_search(my_list, 7))
print(binary_search(my_list, 80))
选择排序:
数组 | 链表 | |
读取 | O(1) | O(n) |
插入 | O(n) | O(1) |
删除 | O(n) | O(1) |
递归:
- 递归条件:调用自己
- 基线条件:不再调用自己
- 调用栈:使用方便;但存储详尽信息可能占用大量内存。
- 栈:后进先出,压入和弹出操作
- tips:如果使用循环,程序的性能可能更高;如果使用递归,程序可能更容易理解。
分而治之:
- 思想:找出简单的基线条件;确定如何缩小问题规模,使其符合基线条件。
- tips:编写涉及数组的递归函数时,基线条件通常为空或只包含一个元素。
- 快速排序:https://blog.csdn.net/keil_/article/details/83785691
- 合并排序(归并):https://blog.csdn.net/keil_/article/details/83785691
散列表(python字典,模拟映射关系):
- 散列函数总是将同样的输入映射到相同的索引
- 应用:查找(电话,IP)、防止重复(投票)、缓存
散列表 (平均情况) | 散列表 (最糟情况) | 数组 | 链表 | |
查找 | O(1) | O(n) | O(1) | O(n) |
插入 | O(1) | O(n) | O(n) | O(1) |
删除 | O(1) | O(n) | O(n) | O(1) |
使用散列表时,重要的时避免最糟情况,为此需要避免冲突。
- 较低的填装因子:填装因子 = 已占用位置/总数
- 良好的散列函数:良好的散列函数让数组中的值呈均匀分布
广度优先搜索(非加权图中查找最短路径):
- 广度优先搜索可用于找出两种东西之间的最短距离。
- 图:图模拟一组连接;由节点和边组成。
- 广度优先搜索解决两类问题:
- 从节点A出发,有前往节点B的路吗;
- 从节点A出发,前往B的哪条路径最短。
- 队列:入队;出队;先进先出。
- 拓扑排序:若A任务依赖于B,在列表中A就必须在B后面
- 数:一种特殊的图,其中没有往后指的边。
- 有向图的边为箭头,箭头的方向指定了关系的方向。
- 无向图的边不带箭头,其中关系是双向的。
找到你联系人中的芒果商:
from collections import deque
def person_is_seller(name):
return name[-1] == 'm'
def search(name):
search_queue = deque()
search_queue += graph[name]
searched = []
while search_queue:
person = search_queue.popleft()
if not person in searched:
if person_is_seller(person):
print("The seller is: ", person)
return True
else:
search_queue += graph[person]
searched.append(person)
return False
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"] = []
search("you")
- BFS 常用于找单一的最短路线,它的特点是 "搜到就是最优解"。
- DFS 用于找所有解的问题,它的空间效率高,而且找到的不一定是最优解,必须记录并完成整个搜索,故一般情况下,深搜需要非常高效的剪枝。
狄克斯特拉算法(加权图中最快路径):
tips:仅用于有向无环图。
- 找出最短时间内到达的节点;
- 更新该节点的邻居的开销;
- 重复这个过程,直到对图中的每个节点都这样做了;
- 计算最终路径。
贝尔曼-福德算法(用于包含负权边的图)
贪婪算法(易于实现):
- 每步都选取局部最优解,最终的得到的就是全局最优解。
- 贪婪策略不能获得最优解,但非常接近。
集合覆盖问题
近似算法
NP完全问题:
以难解著称的问题,如旅行商问题和集合覆盖问题。(无法快速解决问题)
特点:
- 元素较少时算法的运行速度非常快,但随着元素数量的增加,速度会变得非常慢。
- 涉及“所有组合”的问题通常是NP完全问题。
- 不能将问题涉及序列(如旅行商问题中的城市序列)且难以解决,它可能就是NP完全问题。
- 如果问题涉及集合(如广播台集合)且难以解决,它可能就是NP完全问题。
- 如果问题可转换为集合覆盖问题或旅行商问题,肯定是NP完全问题。
tips:
- 贪婪算法寻找局部最优解,企图以这种方式获得全局最优解。
- 对于NP完全问题,还没有找到快速解决方案。
- 面临NP完全问题时,最佳的做法时使用近似算法。
- 贪婪算法易于实现、运行快速快,是不错的近似算法。
动态规划:
先解决子问题,再逐步解决大问题。
仅当子问题是离散的才可使用动态规化。
K最近邻:
树:
- 二叉查找树:不能随机访问。
数组 | 二叉查找树 | |
查找 | O(logn) | O(logn) |
插入 | O(n) | O(n) |
删除 | O(n) | O(logn) |
- 反向索引:常用于创建搜索引擎
- 傅里叶变换:适用于处理信号
- 并行算法
- MapReduce 分布式算法