引言:对于一个算法我们评价其是优是劣,应该从两个角度去分析,分别是时间复杂度和空间复杂度,今天这篇博客我们就从折柳昂个方面展开详细讨论并引例分析。
// 请计算一下Func1中++count语句总共执行了多少次?
void Func1(int N)
{
int count = 0;
for (int i = 0; i < N ; ++ i)
{
for (int j = 0; j < N ; ++ j)
{
++count;
}
}
for (int k = 0; k < 2 * N ; ++ k)
{
++count;
}
int M = 10;
while (M--)
{
++count;
}
printf("%d\n", count);
}
这里引入到一个大O渐进表示法:去掉了那些对结果影响不大的项,也就意味着其中有一些项是可以忽略的。下面引入一些示例:
这里本应该是F(N)=2*N+10,但在我们选择了大O渐进法表示了以后,10和2都可以忽略掉,也就是最大的级数就是N。下面两张图与上图思想一致,不做重复讲解。
如下图所示:
冒泡排序:
如上图冒泡排序,最好情况下是从头到尾排一次序,那么有几个数N,就是O(N),最坏的情况就是到最后一个数了才排好序,那么这个时候就要从头加到尾,这便是等差数列求和,此时最高级数为N^2。
二分查找:
如上图,是一个二分查找,最好的情况就是正中间的那个就是,也就是O(1),最坏的情况,就是不断地二分,直到分不下去的时候才找到,这种情况的话就是2*2*......*2=N,也就是logN。
斐波那契数列:
下面说一道力扣上的题:
这里有三个方法
1.排序+二分查找,这个时间复杂度为O(N*logN),明显不符合题意,所以舍弃该方法
2.异或
先交代码:
int missingNumber(int * nums,int numbersize)
{
int val=0;
for(int i=0;i<numbersize;i++)
{
val^=nums[i];
}
for(int i=0;i<=numbersize;i++)
{
val^=i;
}
return val;
}
这一段代码用到了异或的思想,首先我们要先复习一下异或的原理:1.0与任何数异或还是这个数;2.异或取二进制形式,按位取异;3.举例,1与3异或,再次与3异或,还是1。
该段代码就用到了3这条性质,第一个for是用来遍历整个数组的,也就是相当于把0~n这些数字全都存储到val里,此时是缺一个数的;第二个for根据性质3,相当于一层一层剥去val的外衣,最后因为val会与所有数取异或,这样只被取一次异或的小朋友就出来了。
3.全取和,一个一个减
int missingNumber(int * nums,int numbersize)
{
int sum=numbersize*(numbersize+1)/2;
for(int i=0;i<numbersize;i++)
{
sum-=nums[i];
}
return sum;
}
该代码的时间复杂度也是O(N)也符合题意,而且比上一个方法好想一点。
总结:
1.掌握时间复杂度的概念,并认真理解示例内容;
2.加深对冒泡排序,二分查找,斐波那契数列原理的理解;
3.对力扣习题深入理解。