一、时间复杂度
- 时间复杂度跟数据规模相关
例:在数量级20以下O(n2)时间复杂度要好于O(n)
1、复杂表达式简化
- 描述时间复杂度
(1)只保留最高项
(2)忽略常数项
例:n2+n = n(n+1)
保留最高项 n的平方、去掉常数项1、最后时间复杂度就是O(n方)
- O(logn)忽略底数影响
- 递归算法的时间复杂度 log2x
递归算法的时间复杂度 = 递归次数 * 每次递归中的操作次数(乘法)
'''
递归求x的n次方 1次递归 * 每次数据规模都除以2即操作次数log2x = O(log2x)
'''
def fun3(x,n):
if n == 0:
return 1
t = fun3(x,int(n/2))
if n % 2 == 0:
return t * t
else:
return t * t * x
'''
递归求x的n次方 2的m次方-1次递归(二叉树节点数、深度为K的二叉树的最多节点数是2的k方-1) * 每次数据规模都除以2即log2x = O(n)
两个函数相比、递归次数变少、递归次数冗余
代码优化方向:减少递归调用次数、使用变量、增加空间复杂度
'''
def fun4(x,n):
if n == 0:
return 1
if n % 2 == 0:
return fun4(x,int(n/2)) * fun4(x,int(n/2))
else:
return fun4(x,int(n/2)) * fun4(x,int(n/2)-1) * x
通常OJ系统判定超时时间是1s、估算出N是多大时O(n)会超时、则就要考虑O(logn)方法了
2、编程语言的内存管理
- Python(万物皆对象)通过私有堆空间管理内存、所有Python对象和数据结构都存储在私有堆空间中、程序员没有访问堆的权限、只有解释器才可以。
- 就是因为Python将内存操作封装得很好、所以Python的基本数据类型所占的内存远大于纯数据类型所占的内存
- python、Java不需要考虑内存泄露、虚拟机有内存回收机制
例:C++一个int型数据占4个字节的存储空间、使用Python申请一个int型、所占空间远大于4个字节
3、内存对齐
- 只要是跨平台的编程语言都存在内存对齐、包括C++、java、python
- 内存对齐的原因:
1、平台原因、为了使得程序在多平台运行、而某些平台只能在一些地址处获取特定类型的数据、否则硬件抛异常、
2、硬件原因、经过内存对齐、CPU访问内存的速度会大大提升
- 内存对齐和非内存对齐的区别
CPU读取内存按照块进行读取、块的大小可以是2、4、8、16、具体取决于硬件
例:假设CPU按照4字节块读取int类型的数据
- 1字节的char占用了4字节空间、空了3个、int数据从4开始、内存对齐直接读取4567、只需要一次寻址
- 非内存对齐需要先读取0123、读取4567、合并地址后1234才是需要的、需要两次寻址
char0 | 1 | 2 | 3 | int4 | int5 | int6 | int7 |
char0 | int1 | int2 | int3 | int4 | int5 | int6 | int7 |
二、空间复杂度
- 大致评估程序运行时占用内存的大小、不包括可执行文件、
- 空间复杂度O(1)&&O(n)区别:
消耗内存空间不随着n的变化而变化就是O(1),反之,就是O(n)
# 变量j 该段代码的空间复杂度就是O(1)
j = 0
for i in range(0,10):
print("hahahah")
# 变量j 该段代码的空间复杂度就是O(n)
j = 0
for j in range(0,10):
print("hahahah")
- 递归算法的空间复杂度
递归算法的空间复杂度 = 每次递归的空间复杂度*递归深度
每次递归所需要的空间都被压到调用栈里、一次递归结束、这个栈就把本次递归的数据“弹出去”、栈的最大长度就是递归的深度
- 以空间换时间优化思路:使用哈希时间复杂度一般是O(1)