1,常底数是无所谓的,logaN/logbN = logab, 是一个常数数组
2,时间复杂度:
代码段执行次数累加性能优化
空间复杂度:
除了输入自己所占的空间以外,用于计算的所必须的空间量数据结构
时间复杂度从小到大
O(1)<O(logn)<O(n)<O(nlogn)<O(n²)<O(n³)<O(2ⁿ)<O(n!)
因此,O(n) 可否优化 O(logn)?优化关键闭包
3,Ep12 时间复杂度级数
算数级数,与末项平房同阶,
1+2+3+...n = O(n^2)ide
幂方级数,比幂次高出一阶:
1+2^2+3^2+4^2 +... n^2 = O(n^3);
1+2^3+3^3+4^3 +... n^3= O(n^4);
1+2^4+3^4+4^4+... n^4 = O(n^5); 函数
几何级数(a>1):与末项同阶
a^0+a^1+a^2+... a^n = (a^(n+1) - 1)/(a-1) = O(a^n)
1+2+4+8 +... 2^n = 2^(n+1) -1 = O(2^n)post
4,循环与级数的关系性能
for(let i = 0; i < n; i++) for(let j = 0; i < n; j++) 坐标轴造成正方形,O(n^2) for(let i = 0; i < n; i++) for(let j = 0; i < j; j++) 坐标轴造成三角形,O(n^2)
5,冰与火之歌:时间与空间复杂度优化
分治:将原问题分解为若干个规模较小但相似于原问题的子问题(Divide),「递归」的求解这些子问题(Conquer),而后再合并这些子问题的解来创建原问题的解。
递归算法是一种直接或者间接调用自身函数或者方法的算法。通俗来讲,递归算法的实质是把问题分解成规模缩小的同类问题的子问题,而后递归调用方法来表示问题的解。它有以下特色:
1. 一个问题的解能够分解为几个子问题的解 2. 这个问题与分解以后的子问题,除了数据规模不一样,求解思路彻底同样 3. 存在递归终止条件,即必须有一个明确的递归结束条件,称之为递归出口
递归算法的世界复杂度,得分好几种
第一种:
递归中进行一次递归调用的复杂度分析,如:二分查找法
无论怎么样,最多调用了一次递归调用而已,这时候时间复杂度看何时跳出递归
第二种:
递归中进行屡次递归调用的复杂度分析
好比说斐波拉契数列,屡次调用自身
因此时间复杂度等于递归树中节点数总和,就是代码计算的调用次数。
T(n) = 各层递归实例所需时间之和
= O(1) * (2^0 + 2 ^1 + ...2^n)
= O(1) * (2^(n+1) - 1)
= O(2^n)
空间复杂度:
一个程序执行时除了须要存储空间和存储自己所使用的指令、常数、变量和输入数据外,还须要一些对数据进行操做的工做单元和存储一些为现实计算所需信息的辅助空间。
6,从一个数组中找出最大的两个数
算法一
先遍历一遍,找出最大值的位置,x1, 时间复杂度为 n-1
再遍历一遍,从剩下的n-2个数中,找最大值,时间复杂度为 n-2
总共 O(2n-3) = O(n)
算法二
x1是小值,x2是大数
若是值比x2大,替换x2
若是 x1<num<x2, 替换x1
时间复杂度O(n)
算法三
左边找最大L1,右边找最大 R1
L1<R1, 要么找右边边第二大
else, 要么找左边第二大
7,看动画轻松理解递归与动态规划
动态规划能解决的问题分治策略确定能解决,只是运行时间长了。所以,分治策略通常用来解决子问题相互对立的问题,称为标准分治,而动态规划用来解决子问题重叠的问题。
将「动态规划」的概念关键点抽离出来描述就是这样的:
1.动态规划法试图只解决每一个子问题一次
2.一旦某个给定子问题的解已经算出,则将其记忆化存储,以便下次须要同一个子问题解之时直接查表。
8.JavaScript调用栈、尾递归和手动优化
尾调用:
就是一个函数执行的最后一步是将另一个函数调用并返回。
通常来讲,若是方法a调用方法b, 那么b放到栈顶,栈指针指向栈顶, 当前帧是b, 调用帧是a,
当函数B执行完成后,还须要将执行权返回A,那么函数A内部的变量,调用函数B的位置等信息都必须保存在调用帧A中。否则,当函数B执行完继续执行函数A时,就会乱套。
那么如今,咱们将函数B放到了函数A的最后一步调用(即尾调用),那还有必要保留函数A的栈帧么?固然不用,由于以后并不会再用到其调用位置、内部变量。所以直接用函数B的栈帧取代A的栈帧便可。固然,若是内层函数使用了外层函数的变量,那么就仍然须要保留函数A的栈帧,典型例子便是闭包。
总得来讲,若是全部函数的调用都是尾调用,那么调用栈的长度就会小不少,这样须要占用的内存也会大大减小。这就是尾调用优化的含义。
// 尾调用错误示范1.0 function f(x){ let y = g(x); return y; } // 尾调用错误示范2.0 function f(x){ return g(x) + 1; } // 尾调用错误示范3.0 function f(x) { g(x); // 这一步至关于g(x) return undefined } 1.0最后一步为赋值操做,2.0最后一步为加法运算操做,3.0隐式的有一句return undefined