算法初步
算法研究的是时空复杂度,它具有有穷性,确定性,可行性,还有输入/输出等特点
一、算法分类
- 穷举(万能算法):求N个数的全排列、8皇后问题
- 分而治之(减而治之):二分查找——减而治之、归并排序——分而治之
- 贪心:最小生成树 Prim, Kruskal、单源最短路 Dijkstra
- 动态规划:背包、士兵路径
二、复杂度
时空复杂度:使用大O记号(最坏情况,忽略常数系数)
时间:基本操作次数(汇编指令条数)
空间:占用内存字节数
区别:空间可以再利用 —> 时空互换(Hash表)
复杂度从小到大排序有:
O(1):基本运算,+,-,*,/,%,寻址
O(
log(n)
log
(
n
)
):二分查找
O(
n−−√
n
):枚举约数
O(n):线性查找、读入n个数
O(
n2
n
2
):朴素最近点对、快速排序的复杂度
O(
n3
n
3
):Floyd最短路、普通矩阵乘法
O(
nlog(n)
n
log
(
n
)
):归并排序、快速排序的期望复杂度、基于比较排序的算法下界
O(
2n
2
n
) :枚举全部的子集
O(n!):枚举全排列
总结:
优秀的时间复杂度: O(1) < O(
log(n)
log
(
n
)
) < O(
n−−√
n
)) < O(n) < O(
nlog(n)
n
log
(
n
)
)
可能可以优化: O(
n2
n
2
) < O(
n3
n
3
) < O(
2n
2
n
) < O(n!)
常见时间复杂度分析方法:
估算时常认为计算机一秒可以处理1亿条指令,2的27次方即超过1亿
- 输入输出(输入n个数即有O(n))
- 数循环次数(循环n次的嵌套循环数次方)
- 均摊分析(多个操作,一起算时间复杂度)
MULTIPOP的队列:可以一次性出队k个元素,每个元素只出入队列一次。复杂度O(1)
动态数组尾部插入操作(vector):一旦元素超过容量限制,则扩大一倍,再复制。
三、例题:最大子数组和
给定数组a[1…n],求最大子数组和,即找出1<=i<=j<=n,使a[i]+a[i+1]+…+a[j]最大
介绍三个算法:
暴力枚举 O(n3)
优化枚举 O(n2)
贪心法 O(n)
- 暴力枚举:三重循环
for i → 1 to n
for j → i to n
sum → a[i]+..+a[j]
ans → max(ans, sum)
时间复杂度 O( n3 n 3 ) 附加空间复杂度 O(1) - 优化枚举:两重循环
for i → 1 to n
sum → 0
for j → i to n
sum → sum + a[j]
ans → max(ans, sum)
时间复杂度 O( n2 n 2 ) 附加空间复杂度 O(1) - 贪心法:一重循环
sum → 0
ans → 0
for i → 1 to n
sum → sum + a[i]
ans → max(sum, ans)
if (sum < 0) sum → 0
时间复杂度 O(n) 附加空间复杂度 O(1) - 其他,用变量替换就可以得到贪心法!!!
si → 0
minsi → 0
ans → 0
for j → 1 to n
if (si < minsi) minsi → si
if (si + a[j]- minsi > ans) ans → sj - minsi
si += a[j]
用 sum 代替 si-minsi,则 minsi → si 变成 sum → 0