时间复杂度是评估算法执行效率变化趋势的一种表达方式. 它表达的是一种增长曲线趋势, 而不具体的执行时间.
时间复杂度用大 O 表示法来表示, 他具体的公式是
T(n)=O(f(n))
f(n) 是数学公式中对于函数的一种表达, 我们也可以用代码来平替一下简化理解
1// 针对线性时间复杂度2function f1(n) {3return n4}56// 针对平方时间复杂度7function f2(n) {8return n * n9}
函数 f1 等价于 O(n)
函数 f2 等价于 O(n2)
线性时间复杂度表示为 O(n), 对应的数学公式就是
y=x
在坐标系中我们可以用一条直线来表示, 这条直线表示的是输入和输出的关系. x 轴表示输入, y 轴表示输出.
例如, 一个普通的循环函数, 时间复杂度为 O(n)
1function fn(n) {2for (let i = 0; i < n; i++) {3console.log(i)4}5}
该函数的执行时间, 会随着输入规模 n 的增大而线性增大, 时间复杂度为 O(n)
平方时间复杂度通常是指嵌套循环, 时间复杂度表示为 O(n2), 如下案例所示
1function fn(n) {2for (let i = 0; i < n; i++) {3for (let j = 0; j < n; j++) {4console.log(i, j)5}6}7}
对应的数学公式是
y=x2
时间复杂度用坐标系表示为
指数时间复杂度通常是指递归, 时间复杂度表示为 O(2n), 如下案例所示
1function fn(n) {2if (n <= 1) return 13return fn(n - 1) + fn(n - 2)4}
对应的数学公式是
y=2x
时间复杂度用坐标系表示为
由于三方工具的bug, 导致曲线无法正常显示, 不过移入鼠标之后可以显示坐标点, 通过移动鼠标可以查看坐标点的变化趋势
对数时间复杂度通常是指二分查找, 时间复杂度表示为 O(log2n), 或者简化为 O(logn), 如下案例所示
1function fn(n) {2let i = 13while (i < n) {4i = i * 25}6}
对应的数学公式是
y=log2x
时间复杂度用坐标系表示为
线性对数时间复杂度通常是指嵌套循环, 一层循环是线性时间复杂度, 另一层循环是对数时间复杂度, 时间复杂度表示为 O(n∗log2n), 或者简化为 O(nlogn), 如下案例所示
1function fn(n) {2for (let i = 0; i < n; i++) {3let j = 14while (j < n) {5j = j * 26}7}8}
对应的数学公式是
y=n∗log2x
时间复杂度用坐标系表示为
一定要注意, 时间复杂度是评估算法执行效率变化趋势的一种表达方式, 而不是具体的执行时间. 因此在实践设计算法中, 我们可能会遇到时间复杂度相同, 但是执行时间却不同的情况.
在考虑最优算法时, 通常也会考虑输入规模, 在输入规模足够大的时候, 时间复杂度越低的算法, 执行效率越高. 大家可以根据具体的经验和场景来选择最优的算法.