目录
一、什么是算法?
算法是解题过程的准确而完整的描述,是一个有限规则的几何,这些规则确定了求解某一类问题的一个运算序列,对于某一类问题的任何初始输入,它能机械的一步一步地计算,并且通过有限的步骤之后,计算终止并产生输出。
二、算法的特征
1.有穷性:算法必须再执行有限步之后结束;
2.确定性:每个步骤必须是确切地定义的;
3.输入:有0个或多个输入;
4.输出:有至少一个输出;
5.可行性:每一步都可以再有限时间内完成。
三、如何评价算法的好坏
1.正确性
2.可读性
3.健壮性(容错性/鲁棒性):对不规范数据的处理能力;
4.时间复杂度
5.空间复杂度
四、时间复杂度
1.定义:衡量程序运行速度的量度,忽略硬件的差异。
定性描述程序运行时间和数据规模n的关系的函数,这个函数即程序执行基本操作(加减、寻址、赋值等简单的数学函数)的次数,记作T(n)。
e.g1:
for(int i=1;i<=k;i++){
ans=(ans+f[n][i])%mod;
}
上述循环中int i=1执行2步,i<=k执行k+1次,i++执行k次,每一次循环内部表达式加法、寻址、取模、赋值各一次,所以一共执行4k+2+k+1+k=6k+3次。
其中每一步都是估计,可能最后结果并不准确,所以只能定性描述,不能得到一个确切的结果。
2.大O表示法:考察n趋近于正无穷时的情况
对于一个描述算法的时间复杂度的函数g(n),如果存在一个常数c>0,当N>1时,对一切n>N都有|g(n)|<=c|f(n)|成立(可以理解为在x0y轴坐标系中存在一个函数图像cf(n)一直在g(n)的上侧),则记作g(n)=O(f(n))。
实际计算时往往直接忽略g(n)的低次项和系数。
e.g2:
//以冒泡排序为例
for(int i=0;i<len-1;i++){
for(int j=0;j<len-1-i;j++){
if(a[j]>a[j+1]){
swap(a[j],a[j+1]);
}
}
}
内层for循环执行n-1,n-2...1次
g(n)=(n-1)C+(n-2)C+...+1C
=1/2(n^2-n)C
去掉系数1/2和C,还有低次项n
g(n)=O(n^2)
3.常见时间复杂度:
- O(1):输入和数据规模无关
- O(logn)->底数为2
- O(√n)
- O(n):线性复杂度
- O(n!)
10^8级别在可接受范围内。
e.g3:
for(int i=2;i<=n;i++){
for(int j=0;j<i-2;j++){
//...
}
}
内层循环共执行1+2+...+n-1=O(n^2)
e.g4:
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
//...
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
//...
}
}
第一个内层循环共执行n-1+n-2+...+1=O(n^2)
第二个内层循环共执行n*n=O(n^2)
所以一共就是O(2n^2)=O(n^2)
e.g5:
for(int i=2;i*i<n;i++){
//...
}
O(√n)
e.g6:
分析问题:
方法一:去重O(n^2),冒泡O(n^2)-->O(n^2)
方法二:快排O(nlogn),遍历O(n)-->O(nlogn)
方法三:O(n)
五、空间复杂度
1.计算机内各种变量的存储:
获取变量存储大小:sizeof(数据类型长度符的关键字/类型说明符/表达式)
int:16~32位二进制(short 16,int,long 32位),int最大值是2147483647
double:64位二进制,科学计数法存储,可能存在精度丢失的问题
float:精度太低,不建议使用
char:8位二进制
bool:8位二进制
8位二进制=1字节
六、总结
在写题目是要养成考虑时空复杂度的习惯,不能盲目的写题。
从今天开始学习算法内容,每次学完新的知识之后会更新相关学习笔记,希望自己能够有一定的收获。