定义:用来评估算法运行效率的一个式子。
例如:此处的O(1) 详单与一个时间单位
接下来我们看下面两个式子:
如果按照上面的定义,那么打印三次相当O(3),下面的循环相当于O(n2+1)
但是实际不是这样的
因为这里的时间单位并不是一个精确的时间单位,而是一个大概估计值 ;在计算机中,打印一次和打印三次的时间差不多;此处的时间复杂度对笔者自己而言有点类似于高数中的无穷小概念。
当算法中出现循环规模使得减半,一定会出现logn。
空间复杂度:用来评估算法内存占用大小的式子
空间复杂度的表示方法和时间复杂度完全一样
由于当前计算机硬件发展迅速,在写算法期间,我们采用“空间换时间”的方式。即时间的重要性大于空间。
递归具有两个特点:
观察上面四个式子,我们发现:
func1(x)没有结束条件,所以不算递归;
func2(x)同样没有结束条件,所以不算递归;
func3(x)属于递归;假如传入x=3,打印3,2,1
func4(x)属于递归;假如传入x=3,打印1,2,3
目的:把圆盘按大小顺序重新摆放到另一根柱子上。
要求:在小圆盘上不能放大圆盘;在三根柱子之间一次只能移动一个圆盘。
对于n个盘子是:
汉诺塔移动次数的递推式:h(n) = 2h(n-1)+1
可得h(64) = 18446744073709551615
如果婆罗门每秒钟搬一个盘子,则总共需要5800亿年。
示例代码如下:
def hanoi(n, a, b, c): # 目的是经过b从a移动到c
if n > 0:
hanoi(n - 1, a, c, b) # 第一步,把n-1个盘子从a经过c移动到b
print("moving from %s to %s" % (a, c)) # 第二步,把第n个盘子从a移动到b
hanoi(n - 1, b, a, c) # 第三步,把n-1个盘子从b经过a移动到c
hanoi(3, "A", "B", "C")
输出结果如下:
输出结果即对应3层的汉诺塔操作步骤。
查找:在一些数据元素中,通过一定的方法找出与给定关键字相同的数据元素的过程。
列表查找(线性表查找):从列表中查找元素
内置列标查找函数:index()
顺序查找:也叫线性查找,从列表第一个元素开始,顺序进行搜索,直到找到元素或搜索到列表最后一个元素为止。
def linear_search(li, val): # li为一个列表;val为目标值
for ind, v in enumerate(li): # 遍历列表
if v == val: # 找到目标值
return ind
else:
return None # 未找到目标值
二分查找:又叫折半查找,从有序列表的初始候选区li[0:n]开始,通过对待查找的值与候选区中间值的比较,可以使后翔安区减少一半。(前提是有序列表;如果是无序列表,若只查找一次,还是采用线性查找较好;若需要查找n次,则先排序。再采样二分查找较好)
假如目前存在一个有序列表:
我们需要从列表中查找元素3:
示例代码如下:
def binary_search(li, val):
left = 0
right = len(li) - 1
while left <= right: # 候选去有数值
# mid = int((left + right) / 2)
mid = (left + right) // 2
if li[mid] == val:
return mid
elif li[mid] > val: # 待查找的值在mid左侧
right = mid - 1
else:
left = mid + 1
else:
return None
li = [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(binary_search(li, 6))
因为二分查找每次使得候选区元素减半,因此时间复杂度为O(logn)。