郑州建站优化,百度竞价排名是哪种方式,深圳网站优化怎么做,小皮怎么创建网站什么是算法
算法的定义是这样的#xff1a;解题方案的准确而完善的描述#xff0c;是一系列解决问题的清晰指令。巴拉巴拉的#xff0c;虽然是一小句但还是不想看#xff08;题外话#xff1a;有时候吧专业名词记下来面试的时候还是挺有用的#xff09;#xff0c;其实…什么是算法
算法的定义是这样的解题方案的准确而完善的描述是一系列解决问题的清晰指令。巴拉巴拉的虽然是一小句但还是不想看题外话有时候吧专业名词记下来面试的时候还是挺有用的其实就是解决一个问题的完整性描述。只不过这个描述就可能是用不同的方式或者说是“语言”了。
算法的效率
既然算法是解决问题的描述那么就像一千个人眼中有一千个阿姆雷特他大姨夫一样解决同一个问题的办法也是多种多样的只是在这过程中我们所使用/消耗的时间或者时间以外的代价计算机消耗的则为内存了不一样。为了更快、更好、更强的发扬奥利奥..哦不提高算法的效率。所以很多时候一个优秀的算法就在于它与其他实现同一个问题的算法相比在时间或空间内存或者时间和空间内存上都得到明显的降低。
所以呢算法的效率主要由以下两个复杂度来评估
时间复杂度评估执行程序所需的时间。可以估算出程序对处理器的使用程度。空间复杂度评估执行程序所需的存储空间。可以估算出程序对计算机内存的使用程度。
设计算法时时间复杂度要比空间复杂度更容易出问题所以一般情况一下我们只对时间复杂度进行研究。一般面试或者工作的时候没有特别说明的话复杂度就是指时间复杂度。 1.0 - 空间复杂度 一个程序的空间复杂度是指运行完一个程序所需内存的大小。利用程序的空间复杂度可以对程序的运行所需要的内存多少有个预先估计。一个程序执行时除了需要存储空间和存储本身所使用的指令、常数、变量和输入数据外还需要一些对数据进行操作的工作单元和存储一些为现实计算所需信息的辅助空间。程序执行时所需存储空间包括以下两部分。 1固定部分。这部分空间的大小与输入/输出的数据的个数多少、数值无关。主要包括指令空间即代码空间、数据空间常量、简单变量等所占的空间。这部分属于静态空间。 2可变空间这部分空间的主要包括动态分配的空间以及递归栈所需的空间等。这部分的空间大小与算法有关。 一个算法所需的存储空间用f(n)表示。S(n)O(f(n)) 其中n为问题的规模S(n)表示空间复杂度。
2.0 - 时间复杂度
接下来我们还需要知道另一个概念时间频度。这个时候你可能会说“不是说好一起学算法吗这些东东是什么赠品吗”。非也非也这是非卖品。
因为一个算法执行所消耗的时间理论上是不能算出来的没错正是理论上so我们任然可以在程序中测试获得。但是我们不可能又没必要对每个算法进行测试只需要知道大概的哪个算法执行所花费的时间多哪个花费的时间少就行了。如果一个算法所花费的时间与算法中代码语句执行次数成正比那么那个算法执行语句越多它的花费时间也就越多。我们把一个算法中的语句执行次数称为时间频度。通常ps:很想知道通常是谁用T(n)表示。
在时间频度T(n)中n又代表着问题的规模当n不断变化时T(n)也会不断地随之变化。为了了解这个变化的规律时间复杂度这一概念就被引入了。一般情况下算法基础本操作的重复执行次数为问题规模n的某个函数用也就是时间频度T(n)。如果有某个辅助函数f(n)当趋于无穷大的时候T(n)/f(n)的极限值是不为零的某个常数那么f(n)是T(n)的同数量级函数记作T(n)O(f(n))被称为算法的渐进时间复杂度又简称为时间复杂度。
2.1 - 大O表示法
用O(n)来体现算法时间复杂度的记法被称作大O表示法
一般我们我们评估一个算法都是直接评估它的最坏的复杂度。
大O表示法O(f(n))中的f(n)的值可以为1、n、logn、n^2 等所以我们将O(1)、O(n)、O(logn)、O( n^2 )分别称为常数阶、线性阶、对数阶和平方阶。下面我们来看看推导大O阶的方法
推导大O阶
推导大O阶有一下三种规则
用常数1取代运行时间中的所有加法常数只保留最高阶项去除最高阶的常数
举好多栗子
常数阶 let sum 0, n 10; // 语句执行一次
let sum (1n)*n/2; // 语句执行一次
console.log(The sum is : ${sum}) //语句执行一次
这样的一段代码它的执行次数为 3 然后我们套用规则1则这个算法的时间复杂度为O(1)也就是常数阶。
再例如如果算法的执行时间不随着问题规模n的增加而增长即使算法中有上千条语句其执行时间也不过是一个较大的常数。此类算法的时间复杂度是O(1)。 x91; y100; while(y0) if(x100) {xx-10;y–;} else x; 解答 T(n)O(1) 这个程序看起来有点吓人总共循环运行了1000次但是我们看到n没有?这段程序的运行是和n无关的就算它再循环一万年我们也不管他只是一个常数阶的函数
线性阶
let i 0; // 语句执行一次
while (i n) { // 语句执行n次console.log(Current i is ${i}); //语句执行n次i; // 语句执行n次}
这个算法中代码总共执行了 3n 1次根据规则 2-3因此该算法的时间复杂度是O(n)。
对数阶
let number 1; // 语句执行一次
while (number n) { // 语句执行logn次number * 2; // 语句执行logn次
}
上面的算法中number每次都放大两倍我们假设这个循环体执行了m次那么2^m n即m logn所以整段代码执行次数为1 2*logn则f(n) logn时间复杂度为O(logn)。
平方阶
for (let i 0; i n; i) { // 语句执行n次for (let j 0; j n; j) { // 语句执行n^2次console.log(I am here!); // 语句执行n^2}
}
上面的嵌套循环中代码共执行 2*n^2 n则f(n) n^2。所以该算法的时间复杂度为O(n^2 )
例如当有若干个循环语句时算法的时间复杂度是由嵌套层数最多的循环语句中最内层语句的频度f(n)决定的。 x1; for(i1;in;i) for(j1;ji;j) for(k1;kj;k) x; 该程序段中频度最大的语句是(5)内循环的执行次数虽然与问题规模n没有直接关系但是却与外层循环的变量取值有关而最外层循环的次数直接与n有关因此可以从内层循环向外层分析语句(5)的执行次数 则该程序段的时间复杂度为T(n)O(n3/6低次项)O(n3)
常见时间复杂度的比较
O(1)O(logn)O(n)O(nlogn)O(n²)O(n³)O(2ⁿ)O(n!) 计算空间复杂度
首先要明确一个概念变量的内存分配发生在定义的时候 忽略常数用O(1)表示 递归算法的空间复杂度递归深度N*每次递归所要的辅助空间 对于单线程来说递归有运行时堆栈求的是递归最深的那一次压栈所耗费的空间的个数因为递归最深的那一次所耗费的空间足以容纳它所有递归过程。 a 0 b 0 print(a,b) 它的空间复杂度OnO1
def fun(n): k 10 if n k: return n else: return fun(n) 递归实现调用fun函数每次都创建1个变量k。调用n次空间复杂度On*1On)。
for(i0;in;): temp i 变量的内存分配发生在定义的时候因为temp的定义是循环里边所以是n*O(1)
temp0; for(i0;in;i): temp i temp定义在循环外边所以是1*O(1)