一.为何要学习算法?算法
先来个简单的算法比较:求sum=1+2+3+...+(n-1)+n的结果. 输入整数n,输出 sum
解法一:for循环数组
function sum(n){ var s=0; //执行1次 for(var i=1;i<n+1;i++){ s+=i; //执行n+1次
}
return s; //执行1次
}
解法二:函数
function sum(n){ return n*(n-1)/2; //执行1次 }
很明显,解法二要优于解法一。由于解法二须要运算的次数少。咱们去衡量一个算法的好坏主要是从时间复杂度和空间复杂度来看的,其次才到可读性,可维护性。那么接下来说讲怎么来计算时间复杂度与空间复杂度。学习
二.时间复杂度的计算:spa
推导大O阶来计时间复杂度code
规则:1.用常数1取代运行时间中的全部加法常数(即常数阶都计为O(1) );blog
2.在修改后的运行次数函数中,只保留最高阶项;io
3.若是最高阶项存在且不是1,则去除与这个项相乘的常数for循环
解法一的运行次数: f1(n) = 1+n+1+1=n+3 次 时间复杂度记做 T(n) = O( f1(n) ) //n+3直接舍掉常数,变为n ,名为“线性阶”function
解法二的运行次数: f2(n) = 1次 时间复杂度记做 T(n) = O( f1(1) ) //名为“常数阶”
由此可知解法一随n的增长,运行次数也增长,而解法二始终只需运行一次
对数阶:
function count(n){ var c=1; //执行1次 while(c<n){ c=c*2; //执行log2n次
} return c; }
也就是说2的多少次冪大于n,就运行了多少次。时间复杂度计作O(logn),名为对数阶。
平方阶:
function num(n){ var count=0; for(var i=0;i<n;i++){ //执行 n 次 for(var j=i;j<n;j++){ count++; //执行 n-i 次 } } return count; }
以上代码执行总次数为n+(n-1)+(n-2)+...+1 = n2/2+n/2 次,用大O推导法去掉相加常数n/2,去掉相乘常数1/2,因此时间复杂度为O(n2)
总结:
时间复杂度有多种,这里是讨论常见的阶。经常使用的时间复杂杂耗时的时间从小到大依次为:
O(1) < O(logn) < O(n) < O(nlogn) < O(n2) < O(n3) < O(2n) < O(n!) <O(nn)
扩展:最坏时间复杂度
例:给出一个数组arr,里面有n个随机数,找出arr中的指定数字。那么这个数字有可能出如今数组中的第一个位置,时间复杂度为O(1);也可能出如今数组最后一个位置,时间复杂度为O(n) ,从几率来讲,平均查找时间应该是n/2次。
最坏时间复杂度从字面上就能理解,时间最长的状况,时间不会更长,状况不会更坏了。一般没有特殊说明,咱们计算的时间复杂度都为最坏时间复杂度。
三.算法空间复杂度
算法的空间复杂度并非计算实际占用的空间,而是计算整个算法的辅助空间单元的个数,与问题的规模没有关系。算法的空间复杂度S(n)定义为该算法所耗费空间的数量级。S(n)=O(f(n)) 若算法执行时所须要的辅助空间相对于输入数据量n而言是一个常数,则称这个算法的辅助空间为O(1)。一般,咱们用时间复杂度来衡量算法的优略。