时间空间复杂度、递归、查找

本文介绍了算法的概念,重点讲解了时间复杂度的判断与常见类型,包括O(1), O(n), O(log n)等,并提及空间复杂度。讨论了递归的特性与汉诺塔问题,以及线性查找和二分查找的原理和时间复杂度。" 137779524,22597773,Minio全量与增量备份及还原详解,"['备份策略', '数据管理', '脚本编程', '存储优化', '系统管理']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、算法概念

算法:一个计算过程,解决问题的方法

程序 = 数据结构 + 算法

2、时间复杂度

时间复杂度是用来评估算法运行时间大小的一个式子

用时间复杂度来体现算法运行的快慢
O就是大概的意思,时间复杂度强调的更多的是一个大概的时间

print('hello world')

O(1) :O是数学里上界的意思,可以见到理解为大约,括号里1就是单位,O(1)就是执行了一次,我们把一些基本的操作,比如加减乘除打印等,就叫做时间消耗是1。

for i in range(n):
	print('hello world')

O(n):这个代码是一个循环,大概会运行n次,所以表示成大约O,单位n,n就是一个运行单位

for i in range(n):
	for i in range(n):
		print('hello world')

O(n2):两层循环,定义为n的平方

O(n3):三层循环,定义为n的三次方
四层循环,就是n的四次方

如果打印3次,时间复杂度还是O(1)
两次循环里各带着两个打印,时间复杂度还是O(n2),只留大单位

while n > 1:
	print(n)
	n = n // 2

n = 64输出:
64
32
16
8
4
2
n = 64,代码运行了6次
2^6 = 64
所以时间复杂度记为O(log n)或者O(以2为底n的对数)

当算法出现循环减半的过程,一定会出现log n

2.1 时间复杂度小结:

  • 时间复杂度是用来估计算法运行时间的一个式子(单位)。
  • 一般来说,时间复杂度高的算法比复杂度低的算法慢
  • 常见的时间复杂度(按效率排序):
    O(1) < O(log n) < O(n) < O(nlogn) < O(n^2) < O(n^2logn) < O(n^3)
  • 复杂问题的时间复杂度
    O(!) O(2^n) O(n^n)

2.2 如何简单快速的判断算法复杂度

适用于绝大多数简单的过程

  • 先确定问题规模n,比如循环次数,列表长度
  • 看有没有循环减半过程,若有,就有logn
  • 循环的话,有几层循环就是n的几次方

复杂情况:根据算法执行过程判断

3、空间复杂度

空间复杂度就是用来评估算法内存占用大小的式子

空间复杂度的表示方式与时间复杂度完全一样

  • 若算法只使用了几个变量:O(1)
  • 算法使用了长度为n的一维列表:O(n)
  • 算法使用了m行n列的二维列表:O(mn)
    若是O(n^2),则表示n行n列的二维列表
  • 空间换时间:意思就是算法宁可占用更多内存,也要尽量让时间更快

现在空间复杂度没有时间复杂度讨论的那么多了

4、递归

递归的2个特点:(合法递归)

  • 调用自身
  • 结束条件
def f1(x):
	if x > 0:
		print(x)
		f1(x - 1)

f1(3)

一层一层,先打印,后递归,函数执行过程是从上往下

(大框代表递归,小框代表打印)
在这里插入图片描述
打印结果:3,2,1

def f2(x):
	if x > 0:
		f2(x - 1)
		print(x)

f2(3)

一层一层,先打印,后递归,函数执行过程是从上往下,所以是先打印1

(大框代表递归,小框代表打印)
在这里插入图片描述
运行结果 1,2,3

5、汉诺塔问题

n个盘子时,把上面n-1个盘子看成一个整体

  1. 把n-1个圆盘从A经过C移动到B
  2. 把第n个圆盘从A移动到C
  3. 把n-1个圆盘从B经过A移动到C

此递归终止条件是n=0

def hanoi(n, a, b, c):
	if n > 0:
		hanoi(n-1, a, c, b)  #调用自身,把n-1个盘子从a经过c移动到b
		print(f'{a}-->{c}')  #将第n个从a移动到c,打印出来
		hanoi(n-1, b, a, c)  #把n-1个圆盘从B经过A移动到C

hanoi(3, 'A', 'B', 'C')  #abc三个盘子名字分别传字符串ABC

汉诺塔移动次数的递推式:

h(x) = 2h(x - 1) + 1
(两次调用自身,一次打印)

6、查找

查找:在一些数据元素中,通过一定的方法找出与给定关键字相同的数据元素的过程。

列表查找(线性表查找):从列表中查找指定元素

  • 输入:列表、待查找元素
  • 输出:元素下标(未找到元素时一般返回None或-1,因为下标都是从0开始的,所以返回-1表示没有查到)

python内置列表查找函数:index()

index()是实现线性查找方式的
二分查找列表必须是有序列表

6.1 顺序查找

顺序查找:也叫线性查找,从列表第一个元素开始,顺序进行搜索,直到找到元素或搜索到列表最后一个元素为止。(从头走到尾,如果中间找到就停掉,返回下标)

def linear_search(li, val):  #输入有一个列表,还有待查找元素
	for ind, v in enumerate(li):   #值和下标都需要
		if v == val:
			return ind  #返回下标
	else:   #如果循环执行完毕还没有找到
		return None

时间复杂度:O(n)

6.2 二分查找

二分查找:又叫折半查找,从有序列表的初始候选区li[0:n]开始,通过对待查找的值与候选区中间值的比较,可以使候选区减少一半

输入:列表、待查找元素

维护候选区:用变量left和right ,left指向第一个元素,right指向最后一个元素,初始left=0,right=n-1,n为列表长度

中间元素指向:mid=(left + right)/ 2

若候选区在mid左边,就让right = mid - 1

接下来,若候选区在mid右边,就让left = mid + 1

(left > right时,候选区没有值就结束算法,说明找不到)

def binary_search(li, val):
	left = 0
	right = len(li) - 1  #长度减1
	while left <= right:  #候选区有值
		mid = (left + right) // 2  #整除,因为是下标
		if li[mid] == val:
			return mid   #返回下标
		elif li[mid] > val:  #待查找的值在mid左侧
			right = mid - 1
		else:  # li[mid] < val 待查找的值在mid右侧
			left = mid + 1
	else:  #while条件不满足,没找到
		return None

时间复杂度:O(log n) 减半

二分查找比线性查找效率高

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值